feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
1196
jdkSrc/jdk8/sun/security/provider/AuthPolicyFile.java
Normal file
1196
jdkSrc/jdk8/sun/security/provider/AuthPolicyFile.java
Normal file
File diff suppressed because it is too large
Load Diff
463
jdkSrc/jdk8/sun/security/provider/ByteArrayAccess.java
Normal file
463
jdkSrc/jdk8/sun/security/provider/ByteArrayAccess.java
Normal file
@@ -0,0 +1,463 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import static java.lang.Integer.reverseBytes;
|
||||
import static java.lang.Long.reverseBytes;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* Optimized methods for converting between byte[] and int[]/long[], both for
|
||||
* big endian and little endian byte orders.
|
||||
*
|
||||
* Currently, it includes a default code path plus two optimized code paths.
|
||||
* One is for little endian architectures that support full speed int/long
|
||||
* access at unaligned addresses (i.e. x86/amd64). The second is for big endian
|
||||
* architectures (that only support correctly aligned access), such as SPARC.
|
||||
* These are the only platforms we currently support, but other optimized
|
||||
* variants could be added as needed.
|
||||
*
|
||||
* NOTE that ArrayIndexOutOfBoundsException will be thrown if the bounds checks
|
||||
* failed.
|
||||
*
|
||||
* This class may also be helpful in improving the performance of the
|
||||
* crypto code in the SunJCE provider. However, for now it is only accessible by
|
||||
* the message digest implementation in the SUN provider.
|
||||
*
|
||||
* @since 1.6
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
final class ByteArrayAccess {
|
||||
|
||||
private ByteArrayAccess() {
|
||||
// empty
|
||||
}
|
||||
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
|
||||
// whether to use the optimized path for little endian platforms that
|
||||
// support full speed unaligned memory access.
|
||||
private static final boolean littleEndianUnaligned;
|
||||
|
||||
// whether to use the optimzied path for big endian platforms that
|
||||
// support only correctly aligned full speed memory access.
|
||||
// (Note that on SPARC unaligned memory access is possible, but it is
|
||||
// implemented using a software trap and therefore very slow)
|
||||
private static final boolean bigEndian;
|
||||
|
||||
private final static int byteArrayOfs = unsafe.arrayBaseOffset(byte[].class);
|
||||
|
||||
static {
|
||||
boolean scaleOK = ((unsafe.arrayIndexScale(byte[].class) == 1)
|
||||
&& (unsafe.arrayIndexScale(int[].class) == 4)
|
||||
&& (unsafe.arrayIndexScale(long[].class) == 8)
|
||||
&& ((byteArrayOfs & 3) == 0));
|
||||
|
||||
ByteOrder byteOrder = ByteOrder.nativeOrder();
|
||||
littleEndianUnaligned =
|
||||
scaleOK && unaligned() && (byteOrder == ByteOrder.LITTLE_ENDIAN);
|
||||
bigEndian =
|
||||
scaleOK && (byteOrder == ByteOrder.BIG_ENDIAN);
|
||||
}
|
||||
|
||||
// Return whether this platform supports full speed int/long memory access
|
||||
// at unaligned addresses.
|
||||
// This code was copied from java.nio.Bits because there is no equivalent
|
||||
// public API.
|
||||
private static boolean unaligned() {
|
||||
String arch = java.security.AccessController.doPrivileged
|
||||
(new sun.security.action.GetPropertyAction("os.arch", ""));
|
||||
return arch.equals("i386") || arch.equals("x86") || arch.equals("amd64")
|
||||
|| arch.equals("x86_64") || arch.equals("ppc64") || arch.equals("ppc64le")
|
||||
|| arch.equals("aarch64");
|
||||
}
|
||||
|
||||
/**
|
||||
* byte[] to int[] conversion, little endian byte order.
|
||||
*/
|
||||
static void b2iLittle(byte[] in, int inOfs, int[] out, int outOfs, int len) {
|
||||
if ((inOfs < 0) || ((in.length - inOfs) < len) ||
|
||||
(outOfs < 0) || ((out.length - outOfs) < len/4)) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
if (littleEndianUnaligned) {
|
||||
inOfs += byteArrayOfs;
|
||||
len += inOfs;
|
||||
while (inOfs < len) {
|
||||
out[outOfs++] = unsafe.getInt(in, (long)inOfs);
|
||||
inOfs += 4;
|
||||
}
|
||||
} else if (bigEndian && ((inOfs & 3) == 0)) {
|
||||
inOfs += byteArrayOfs;
|
||||
len += inOfs;
|
||||
while (inOfs < len) {
|
||||
out[outOfs++] = reverseBytes(unsafe.getInt(in, (long)inOfs));
|
||||
inOfs += 4;
|
||||
}
|
||||
} else {
|
||||
len += inOfs;
|
||||
while (inOfs < len) {
|
||||
out[outOfs++] = ((in[inOfs ] & 0xff) )
|
||||
| ((in[inOfs + 1] & 0xff) << 8)
|
||||
| ((in[inOfs + 2] & 0xff) << 16)
|
||||
| ((in[inOfs + 3] ) << 24);
|
||||
inOfs += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Special optimization of b2iLittle(in, inOfs, out, 0, 64)
|
||||
static void b2iLittle64(byte[] in, int inOfs, int[] out) {
|
||||
if ((inOfs < 0) || ((in.length - inOfs) < 64) ||
|
||||
(out.length < 16)) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
if (littleEndianUnaligned) {
|
||||
inOfs += byteArrayOfs;
|
||||
out[ 0] = unsafe.getInt(in, (long)(inOfs ));
|
||||
out[ 1] = unsafe.getInt(in, (long)(inOfs + 4));
|
||||
out[ 2] = unsafe.getInt(in, (long)(inOfs + 8));
|
||||
out[ 3] = unsafe.getInt(in, (long)(inOfs + 12));
|
||||
out[ 4] = unsafe.getInt(in, (long)(inOfs + 16));
|
||||
out[ 5] = unsafe.getInt(in, (long)(inOfs + 20));
|
||||
out[ 6] = unsafe.getInt(in, (long)(inOfs + 24));
|
||||
out[ 7] = unsafe.getInt(in, (long)(inOfs + 28));
|
||||
out[ 8] = unsafe.getInt(in, (long)(inOfs + 32));
|
||||
out[ 9] = unsafe.getInt(in, (long)(inOfs + 36));
|
||||
out[10] = unsafe.getInt(in, (long)(inOfs + 40));
|
||||
out[11] = unsafe.getInt(in, (long)(inOfs + 44));
|
||||
out[12] = unsafe.getInt(in, (long)(inOfs + 48));
|
||||
out[13] = unsafe.getInt(in, (long)(inOfs + 52));
|
||||
out[14] = unsafe.getInt(in, (long)(inOfs + 56));
|
||||
out[15] = unsafe.getInt(in, (long)(inOfs + 60));
|
||||
} else if (bigEndian && ((inOfs & 3) == 0)) {
|
||||
inOfs += byteArrayOfs;
|
||||
out[ 0] = reverseBytes(unsafe.getInt(in, (long)(inOfs )));
|
||||
out[ 1] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 4)));
|
||||
out[ 2] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 8)));
|
||||
out[ 3] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 12)));
|
||||
out[ 4] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 16)));
|
||||
out[ 5] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 20)));
|
||||
out[ 6] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 24)));
|
||||
out[ 7] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 28)));
|
||||
out[ 8] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 32)));
|
||||
out[ 9] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 36)));
|
||||
out[10] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 40)));
|
||||
out[11] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 44)));
|
||||
out[12] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 48)));
|
||||
out[13] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 52)));
|
||||
out[14] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 56)));
|
||||
out[15] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 60)));
|
||||
} else {
|
||||
b2iLittle(in, inOfs, out, 0, 64);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* int[] to byte[] conversion, little endian byte order.
|
||||
*/
|
||||
static void i2bLittle(int[] in, int inOfs, byte[] out, int outOfs, int len) {
|
||||
if ((inOfs < 0) || ((in.length - inOfs) < len/4) ||
|
||||
(outOfs < 0) || ((out.length - outOfs) < len)) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
if (littleEndianUnaligned) {
|
||||
outOfs += byteArrayOfs;
|
||||
len += outOfs;
|
||||
while (outOfs < len) {
|
||||
unsafe.putInt(out, (long)outOfs, in[inOfs++]);
|
||||
outOfs += 4;
|
||||
}
|
||||
} else if (bigEndian && ((outOfs & 3) == 0)) {
|
||||
outOfs += byteArrayOfs;
|
||||
len += outOfs;
|
||||
while (outOfs < len) {
|
||||
unsafe.putInt(out, (long)outOfs, reverseBytes(in[inOfs++]));
|
||||
outOfs += 4;
|
||||
}
|
||||
} else {
|
||||
len += outOfs;
|
||||
while (outOfs < len) {
|
||||
int i = in[inOfs++];
|
||||
out[outOfs++] = (byte)(i );
|
||||
out[outOfs++] = (byte)(i >> 8);
|
||||
out[outOfs++] = (byte)(i >> 16);
|
||||
out[outOfs++] = (byte)(i >> 24);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store one 32-bit value into out[outOfs..outOfs+3] in little endian order.
|
||||
static void i2bLittle4(int val, byte[] out, int outOfs) {
|
||||
if ((outOfs < 0) || ((out.length - outOfs) < 4)) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
if (littleEndianUnaligned) {
|
||||
unsafe.putInt(out, (long)(byteArrayOfs + outOfs), val);
|
||||
} else if (bigEndian && ((outOfs & 3) == 0)) {
|
||||
unsafe.putInt(out, (long)(byteArrayOfs + outOfs), reverseBytes(val));
|
||||
} else {
|
||||
out[outOfs ] = (byte)(val );
|
||||
out[outOfs + 1] = (byte)(val >> 8);
|
||||
out[outOfs + 2] = (byte)(val >> 16);
|
||||
out[outOfs + 3] = (byte)(val >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* byte[] to int[] conversion, big endian byte order.
|
||||
*/
|
||||
static void b2iBig(byte[] in, int inOfs, int[] out, int outOfs, int len) {
|
||||
if ((inOfs < 0) || ((in.length - inOfs) < len) ||
|
||||
(outOfs < 0) || ((out.length - outOfs) < len/4)) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
if (littleEndianUnaligned) {
|
||||
inOfs += byteArrayOfs;
|
||||
len += inOfs;
|
||||
while (inOfs < len) {
|
||||
out[outOfs++] = reverseBytes(unsafe.getInt(in, (long)inOfs));
|
||||
inOfs += 4;
|
||||
}
|
||||
} else if (bigEndian && ((inOfs & 3) == 0)) {
|
||||
inOfs += byteArrayOfs;
|
||||
len += inOfs;
|
||||
while (inOfs < len) {
|
||||
out[outOfs++] = unsafe.getInt(in, (long)inOfs);
|
||||
inOfs += 4;
|
||||
}
|
||||
} else {
|
||||
len += inOfs;
|
||||
while (inOfs < len) {
|
||||
out[outOfs++] = ((in[inOfs + 3] & 0xff) )
|
||||
| ((in[inOfs + 2] & 0xff) << 8)
|
||||
| ((in[inOfs + 1] & 0xff) << 16)
|
||||
| ((in[inOfs ] ) << 24);
|
||||
inOfs += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Special optimization of b2iBig(in, inOfs, out, 0, 64)
|
||||
static void b2iBig64(byte[] in, int inOfs, int[] out) {
|
||||
if ((inOfs < 0) || ((in.length - inOfs) < 64) ||
|
||||
(out.length < 16)) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
if (littleEndianUnaligned) {
|
||||
inOfs += byteArrayOfs;
|
||||
out[ 0] = reverseBytes(unsafe.getInt(in, (long)(inOfs )));
|
||||
out[ 1] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 4)));
|
||||
out[ 2] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 8)));
|
||||
out[ 3] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 12)));
|
||||
out[ 4] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 16)));
|
||||
out[ 5] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 20)));
|
||||
out[ 6] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 24)));
|
||||
out[ 7] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 28)));
|
||||
out[ 8] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 32)));
|
||||
out[ 9] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 36)));
|
||||
out[10] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 40)));
|
||||
out[11] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 44)));
|
||||
out[12] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 48)));
|
||||
out[13] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 52)));
|
||||
out[14] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 56)));
|
||||
out[15] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 60)));
|
||||
} else if (bigEndian && ((inOfs & 3) == 0)) {
|
||||
inOfs += byteArrayOfs;
|
||||
out[ 0] = unsafe.getInt(in, (long)(inOfs ));
|
||||
out[ 1] = unsafe.getInt(in, (long)(inOfs + 4));
|
||||
out[ 2] = unsafe.getInt(in, (long)(inOfs + 8));
|
||||
out[ 3] = unsafe.getInt(in, (long)(inOfs + 12));
|
||||
out[ 4] = unsafe.getInt(in, (long)(inOfs + 16));
|
||||
out[ 5] = unsafe.getInt(in, (long)(inOfs + 20));
|
||||
out[ 6] = unsafe.getInt(in, (long)(inOfs + 24));
|
||||
out[ 7] = unsafe.getInt(in, (long)(inOfs + 28));
|
||||
out[ 8] = unsafe.getInt(in, (long)(inOfs + 32));
|
||||
out[ 9] = unsafe.getInt(in, (long)(inOfs + 36));
|
||||
out[10] = unsafe.getInt(in, (long)(inOfs + 40));
|
||||
out[11] = unsafe.getInt(in, (long)(inOfs + 44));
|
||||
out[12] = unsafe.getInt(in, (long)(inOfs + 48));
|
||||
out[13] = unsafe.getInt(in, (long)(inOfs + 52));
|
||||
out[14] = unsafe.getInt(in, (long)(inOfs + 56));
|
||||
out[15] = unsafe.getInt(in, (long)(inOfs + 60));
|
||||
} else {
|
||||
b2iBig(in, inOfs, out, 0, 64);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* int[] to byte[] conversion, big endian byte order.
|
||||
*/
|
||||
static void i2bBig(int[] in, int inOfs, byte[] out, int outOfs, int len) {
|
||||
if ((inOfs < 0) || ((in.length - inOfs) < len/4) ||
|
||||
(outOfs < 0) || ((out.length - outOfs) < len)) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
if (littleEndianUnaligned) {
|
||||
outOfs += byteArrayOfs;
|
||||
len += outOfs;
|
||||
while (outOfs < len) {
|
||||
unsafe.putInt(out, (long)outOfs, reverseBytes(in[inOfs++]));
|
||||
outOfs += 4;
|
||||
}
|
||||
} else if (bigEndian && ((outOfs & 3) == 0)) {
|
||||
outOfs += byteArrayOfs;
|
||||
len += outOfs;
|
||||
while (outOfs < len) {
|
||||
unsafe.putInt(out, (long)outOfs, in[inOfs++]);
|
||||
outOfs += 4;
|
||||
}
|
||||
} else {
|
||||
len += outOfs;
|
||||
while (outOfs < len) {
|
||||
int i = in[inOfs++];
|
||||
out[outOfs++] = (byte)(i >> 24);
|
||||
out[outOfs++] = (byte)(i >> 16);
|
||||
out[outOfs++] = (byte)(i >> 8);
|
||||
out[outOfs++] = (byte)(i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store one 32-bit value into out[outOfs..outOfs+3] in big endian order.
|
||||
static void i2bBig4(int val, byte[] out, int outOfs) {
|
||||
if ((outOfs < 0) || ((out.length - outOfs) < 4)) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
if (littleEndianUnaligned) {
|
||||
unsafe.putInt(out, (long)(byteArrayOfs + outOfs), reverseBytes(val));
|
||||
} else if (bigEndian && ((outOfs & 3) == 0)) {
|
||||
unsafe.putInt(out, (long)(byteArrayOfs + outOfs), val);
|
||||
} else {
|
||||
out[outOfs ] = (byte)(val >> 24);
|
||||
out[outOfs + 1] = (byte)(val >> 16);
|
||||
out[outOfs + 2] = (byte)(val >> 8);
|
||||
out[outOfs + 3] = (byte)(val );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* byte[] to long[] conversion, big endian byte order.
|
||||
*/
|
||||
static void b2lBig(byte[] in, int inOfs, long[] out, int outOfs, int len) {
|
||||
if ((inOfs < 0) || ((in.length - inOfs) < len) ||
|
||||
(outOfs < 0) || ((out.length - outOfs) < len/8)) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
if (littleEndianUnaligned) {
|
||||
inOfs += byteArrayOfs;
|
||||
len += inOfs;
|
||||
while (inOfs < len) {
|
||||
out[outOfs++] = reverseBytes(unsafe.getLong(in, (long)inOfs));
|
||||
inOfs += 8;
|
||||
}
|
||||
} else if (bigEndian && ((inOfs & 3) == 0)) {
|
||||
// In the current HotSpot memory layout, the first element of a
|
||||
// byte[] is only 32-bit aligned, not 64-bit.
|
||||
// That means we could use getLong() only for offset 4, 12, etc.,
|
||||
// which would rarely occur in practice. Instead, we use an
|
||||
// optimization that uses getInt() so that it works for offset 0.
|
||||
inOfs += byteArrayOfs;
|
||||
len += inOfs;
|
||||
while (inOfs < len) {
|
||||
out[outOfs++] =
|
||||
((long)unsafe.getInt(in, (long)inOfs) << 32)
|
||||
| (unsafe.getInt(in, (long)(inOfs + 4)) & 0xffffffffL);
|
||||
inOfs += 8;
|
||||
}
|
||||
} else {
|
||||
len += inOfs;
|
||||
while (inOfs < len) {
|
||||
int i1 = ((in[inOfs + 3] & 0xff) )
|
||||
| ((in[inOfs + 2] & 0xff) << 8)
|
||||
| ((in[inOfs + 1] & 0xff) << 16)
|
||||
| ((in[inOfs ] ) << 24);
|
||||
inOfs += 4;
|
||||
int i2 = ((in[inOfs + 3] & 0xff) )
|
||||
| ((in[inOfs + 2] & 0xff) << 8)
|
||||
| ((in[inOfs + 1] & 0xff) << 16)
|
||||
| ((in[inOfs ] ) << 24);
|
||||
out[outOfs++] = ((long)i1 << 32) | (i2 & 0xffffffffL);
|
||||
inOfs += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Special optimization of b2lBig(in, inOfs, out, 0, 128)
|
||||
static void b2lBig128(byte[] in, int inOfs, long[] out) {
|
||||
if ((inOfs < 0) || ((in.length - inOfs) < 128) ||
|
||||
(out.length < 16)) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
if (littleEndianUnaligned) {
|
||||
inOfs += byteArrayOfs;
|
||||
out[ 0] = reverseBytes(unsafe.getLong(in, (long)(inOfs )));
|
||||
out[ 1] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 8)));
|
||||
out[ 2] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 16)));
|
||||
out[ 3] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 24)));
|
||||
out[ 4] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 32)));
|
||||
out[ 5] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 40)));
|
||||
out[ 6] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 48)));
|
||||
out[ 7] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 56)));
|
||||
out[ 8] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 64)));
|
||||
out[ 9] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 72)));
|
||||
out[10] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 80)));
|
||||
out[11] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 88)));
|
||||
out[12] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 96)));
|
||||
out[13] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 104)));
|
||||
out[14] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 112)));
|
||||
out[15] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 120)));
|
||||
} else {
|
||||
// no optimization for big endian, see comments in b2lBig
|
||||
b2lBig(in, inOfs, out, 0, 128);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* long[] to byte[] conversion, big endian byte order.
|
||||
*/
|
||||
static void l2bBig(long[] in, int inOfs, byte[] out, int outOfs, int len) {
|
||||
if ((inOfs < 0) || ((in.length - inOfs) < len/8) ||
|
||||
(outOfs < 0) || ((out.length - outOfs) < len)) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
len += outOfs;
|
||||
while (outOfs < len) {
|
||||
long i = in[inOfs++];
|
||||
out[outOfs++] = (byte)(i >> 56);
|
||||
out[outOfs++] = (byte)(i >> 48);
|
||||
out[outOfs++] = (byte)(i >> 40);
|
||||
out[outOfs++] = (byte)(i >> 32);
|
||||
out[outOfs++] = (byte)(i >> 24);
|
||||
out[outOfs++] = (byte)(i >> 16);
|
||||
out[outOfs++] = (byte)(i >> 8);
|
||||
out[outOfs++] = (byte)(i );
|
||||
}
|
||||
}
|
||||
}
|
||||
669
jdkSrc/jdk8/sun/security/provider/ConfigFile.java
Normal file
669
jdkSrc/jdk8/sun/security/provider/ConfigFile.java
Normal file
@@ -0,0 +1,669 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.security.Security;
|
||||
import java.security.URIParameter;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
import javax.security.auth.AuthPermission;
|
||||
import javax.security.auth.login.AppConfigurationEntry;
|
||||
import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
|
||||
import javax.security.auth.login.Configuration;
|
||||
import javax.security.auth.login.ConfigurationSpi;
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.util.PropertyExpander;
|
||||
import sun.security.util.ResourcesMgr;
|
||||
|
||||
/**
|
||||
* This class represents a default implementation for
|
||||
* {@code javax.security.auth.login.Configuration}.
|
||||
*
|
||||
* <p> This object stores the runtime login configuration representation,
|
||||
* and is the amalgamation of multiple static login configurations that
|
||||
* resides in files. The algorithm for locating the login configuration
|
||||
* file(s) and reading their information into this {@code Configuration}
|
||||
* object is:
|
||||
*
|
||||
* <ol>
|
||||
* <li>
|
||||
* Loop through the security properties,
|
||||
* <i>login.config.url.1</i>, <i>login.config.url.2</i>, ...,
|
||||
* <i>login.config.url.X</i>.
|
||||
* Each property value specifies a {@code URL} pointing to a
|
||||
* login configuration file to be loaded. Read in and load
|
||||
* each configuration.
|
||||
*
|
||||
* <li>
|
||||
* The {@code java.lang.System} property
|
||||
* <i>java.security.auth.login.config</i>
|
||||
* may also be set to a {@code URL} pointing to another
|
||||
* login configuration file
|
||||
* (which is the case when a user uses the -D switch at runtime).
|
||||
* If this property is defined, and its use is allowed by the
|
||||
* security property file (the Security property,
|
||||
* <i>policy.allowSystemProperty</i> is set to <i>true</i>),
|
||||
* also load that login configuration.
|
||||
*
|
||||
* <li>
|
||||
* If the <i>java.security.auth.login.config</i> property is defined using
|
||||
* "==" (rather than "="), then ignore all other specified
|
||||
* login configurations and only load this configuration.
|
||||
*
|
||||
* <li>
|
||||
* If no system or security properties were set, try to read from the file,
|
||||
* ${user.home}/.java.login.config, where ${user.home} is the value
|
||||
* represented by the "user.home" System property.
|
||||
* </ol>
|
||||
*
|
||||
* <p> The configuration syntax supported by this implementation
|
||||
* is exactly that syntax specified in the
|
||||
* {@code javax.security.auth.login.Configuration} class.
|
||||
*
|
||||
* @see javax.security.auth.login.LoginContext
|
||||
* @see java.security.Security security properties
|
||||
*/
|
||||
public final class ConfigFile extends Configuration {
|
||||
|
||||
private final Spi spi;
|
||||
|
||||
public ConfigFile() {
|
||||
spi = new Spi();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppConfigurationEntry[] getAppConfigurationEntry(String appName) {
|
||||
return spi.engineGetAppConfigurationEntry(appName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void refresh() {
|
||||
spi.engineRefresh();
|
||||
}
|
||||
|
||||
public final static class Spi extends ConfigurationSpi {
|
||||
|
||||
private URL url;
|
||||
private boolean expandProp = true;
|
||||
private Map<String, List<AppConfigurationEntry>> configuration;
|
||||
private int linenum;
|
||||
private StreamTokenizer st;
|
||||
private int lookahead;
|
||||
|
||||
private static Debug debugConfig = Debug.getInstance("configfile");
|
||||
private static Debug debugParser = Debug.getInstance("configparser");
|
||||
|
||||
/**
|
||||
* Creates a new {@code ConfigurationSpi} object.
|
||||
*
|
||||
* @throws SecurityException if the {@code ConfigurationSpi} can not be
|
||||
* initialized
|
||||
*/
|
||||
public Spi() {
|
||||
try {
|
||||
init();
|
||||
} catch (IOException ioe) {
|
||||
throw new SecurityException(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code ConfigurationSpi} object from the specified
|
||||
* {@code URI}.
|
||||
*
|
||||
* @param uri the {@code URI}
|
||||
* @throws SecurityException if the {@code ConfigurationSpi} can not be
|
||||
* initialized
|
||||
* @throws NullPointerException if {@code uri} is null
|
||||
*/
|
||||
public Spi(URI uri) {
|
||||
// only load config from the specified URI
|
||||
try {
|
||||
url = uri.toURL();
|
||||
init();
|
||||
} catch (IOException ioe) {
|
||||
throw new SecurityException(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public Spi(final Configuration.Parameters params) throws IOException {
|
||||
|
||||
// call in a doPrivileged
|
||||
//
|
||||
// we have already passed the Configuration.getInstance
|
||||
// security check. also this class is not freely accessible
|
||||
// (it is in the "sun" package).
|
||||
|
||||
try {
|
||||
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
|
||||
public Void run() throws IOException {
|
||||
if (params == null) {
|
||||
init();
|
||||
} else {
|
||||
if (!(params instanceof URIParameter)) {
|
||||
throw new IllegalArgumentException
|
||||
("Unrecognized parameter: " + params);
|
||||
}
|
||||
URIParameter uriParam = (URIParameter)params;
|
||||
url = uriParam.getURI().toURL();
|
||||
init();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
} catch (PrivilegedActionException pae) {
|
||||
throw (IOException)pae.getException();
|
||||
}
|
||||
|
||||
// if init() throws some other RuntimeException,
|
||||
// let it percolate up naturally.
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and initialize the entire login Configuration from the
|
||||
* configured URL.
|
||||
*
|
||||
* @throws IOException if the Configuration can not be initialized
|
||||
* @throws SecurityException if the caller does not have permission
|
||||
* to initialize the Configuration
|
||||
*/
|
||||
private void init() throws IOException {
|
||||
|
||||
boolean initialized = false;
|
||||
|
||||
// For policy.expandProperties, check if either a security or system
|
||||
// property is set to false (old code erroneously checked the system
|
||||
// prop so we must check both to preserve compatibility).
|
||||
String expand = Security.getProperty("policy.expandProperties");
|
||||
if (expand == null) {
|
||||
expand = System.getProperty("policy.expandProperties");
|
||||
}
|
||||
if ("false".equals(expand)) {
|
||||
expandProp = false;
|
||||
}
|
||||
|
||||
// new configuration
|
||||
Map<String, List<AppConfigurationEntry>> newConfig = new HashMap<>();
|
||||
|
||||
if (url != null) {
|
||||
/**
|
||||
* If the caller specified a URI via Configuration.getInstance,
|
||||
* we only read from that URI
|
||||
*/
|
||||
if (debugConfig != null) {
|
||||
debugConfig.println("reading " + url);
|
||||
}
|
||||
init(url, newConfig);
|
||||
configuration = newConfig;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Caller did not specify URI via Configuration.getInstance.
|
||||
* Read from URLs listed in the java.security properties file.
|
||||
*/
|
||||
String allowSys = Security.getProperty("policy.allowSystemProperty");
|
||||
|
||||
if ("true".equalsIgnoreCase(allowSys)) {
|
||||
String extra_config = System.getProperty
|
||||
("java.security.auth.login.config");
|
||||
if (extra_config != null) {
|
||||
boolean overrideAll = false;
|
||||
if (extra_config.startsWith("=")) {
|
||||
overrideAll = true;
|
||||
extra_config = extra_config.substring(1);
|
||||
}
|
||||
try {
|
||||
extra_config = PropertyExpander.expand(extra_config);
|
||||
} catch (PropertyExpander.ExpandException peee) {
|
||||
throw ioException("Unable.to.properly.expand.config",
|
||||
extra_config);
|
||||
}
|
||||
|
||||
URL configURL = null;
|
||||
try {
|
||||
configURL = new URL(extra_config);
|
||||
} catch (MalformedURLException mue) {
|
||||
File configFile = new File(extra_config);
|
||||
if (configFile.exists()) {
|
||||
configURL = configFile.toURI().toURL();
|
||||
} else {
|
||||
throw ioException(
|
||||
"extra.config.No.such.file.or.directory.",
|
||||
extra_config);
|
||||
}
|
||||
}
|
||||
|
||||
if (debugConfig != null) {
|
||||
debugConfig.println("reading "+configURL);
|
||||
}
|
||||
init(configURL, newConfig);
|
||||
initialized = true;
|
||||
if (overrideAll) {
|
||||
if (debugConfig != null) {
|
||||
debugConfig.println("overriding other policies!");
|
||||
}
|
||||
configuration = newConfig;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int n = 1;
|
||||
String config_url;
|
||||
while ((config_url = Security.getProperty
|
||||
("login.config.url."+n)) != null) {
|
||||
try {
|
||||
config_url = PropertyExpander.expand
|
||||
(config_url).replace(File.separatorChar, '/');
|
||||
if (debugConfig != null) {
|
||||
debugConfig.println("\tReading config: " + config_url);
|
||||
}
|
||||
init(new URL(config_url), newConfig);
|
||||
initialized = true;
|
||||
} catch (PropertyExpander.ExpandException peee) {
|
||||
throw ioException("Unable.to.properly.expand.config",
|
||||
config_url);
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
||||
if (initialized == false && n == 1 && config_url == null) {
|
||||
|
||||
// get the config from the user's home directory
|
||||
if (debugConfig != null) {
|
||||
debugConfig.println("\tReading Policy " +
|
||||
"from ~/.java.login.config");
|
||||
}
|
||||
config_url = System.getProperty("user.home");
|
||||
String userConfigFile = config_url + File.separatorChar +
|
||||
".java.login.config";
|
||||
|
||||
// No longer throws an exception when there's no config file
|
||||
// at all. Returns an empty Configuration instead.
|
||||
if (new File(userConfigFile).exists()) {
|
||||
init(new File(userConfigFile).toURI().toURL(), newConfig);
|
||||
}
|
||||
}
|
||||
|
||||
configuration = newConfig;
|
||||
}
|
||||
|
||||
private void init(URL config,
|
||||
Map<String, List<AppConfigurationEntry>> newConfig)
|
||||
throws IOException {
|
||||
|
||||
try (InputStreamReader isr
|
||||
= new InputStreamReader(getInputStream(config), "UTF-8")) {
|
||||
readConfig(isr, newConfig);
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
if (debugConfig != null) {
|
||||
debugConfig.println(fnfe.toString());
|
||||
}
|
||||
throw new IOException(ResourcesMgr.getString
|
||||
("Configuration.Error.No.such.file.or.directory",
|
||||
"sun.security.util.AuthResources"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an entry from the Configuration using an application name
|
||||
* as an index.
|
||||
*
|
||||
* @param applicationName the name used to index the Configuration.
|
||||
* @return an array of AppConfigurationEntries which correspond to
|
||||
* the stacked configuration of LoginModules for this
|
||||
* application, or null if this application has no configured
|
||||
* LoginModules.
|
||||
*/
|
||||
@Override
|
||||
public AppConfigurationEntry[] engineGetAppConfigurationEntry
|
||||
(String applicationName) {
|
||||
|
||||
List<AppConfigurationEntry> list = null;
|
||||
synchronized (configuration) {
|
||||
list = configuration.get(applicationName);
|
||||
}
|
||||
|
||||
if (list == null || list.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
AppConfigurationEntry[] entries =
|
||||
new AppConfigurationEntry[list.size()];
|
||||
Iterator<AppConfigurationEntry> iterator = list.iterator();
|
||||
for (int i = 0; iterator.hasNext(); i++) {
|
||||
AppConfigurationEntry e = iterator.next();
|
||||
entries[i] = new AppConfigurationEntry(e.getLoginModuleName(),
|
||||
e.getControlFlag(),
|
||||
e.getOptions());
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh and reload the Configuration by re-reading all of the
|
||||
* login configurations.
|
||||
*
|
||||
* @throws SecurityException if the caller does not have permission
|
||||
* to refresh the Configuration.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void engineRefresh() {
|
||||
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(
|
||||
new AuthPermission("refreshLoginConfiguration"));
|
||||
}
|
||||
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
try {
|
||||
init();
|
||||
} catch (IOException ioe) {
|
||||
throw new SecurityException(ioe.getLocalizedMessage(),
|
||||
ioe);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void readConfig(Reader reader,
|
||||
Map<String, List<AppConfigurationEntry>> newConfig)
|
||||
throws IOException {
|
||||
|
||||
linenum = 1;
|
||||
|
||||
if (!(reader instanceof BufferedReader)) {
|
||||
reader = new BufferedReader(reader);
|
||||
}
|
||||
|
||||
st = new StreamTokenizer(reader);
|
||||
st.quoteChar('"');
|
||||
st.wordChars('$', '$');
|
||||
st.wordChars('_', '_');
|
||||
st.wordChars('-', '-');
|
||||
st.wordChars('*', '*');
|
||||
st.lowerCaseMode(false);
|
||||
st.slashSlashComments(true);
|
||||
st.slashStarComments(true);
|
||||
st.eolIsSignificant(true);
|
||||
|
||||
lookahead = nextToken();
|
||||
while (lookahead != StreamTokenizer.TT_EOF) {
|
||||
parseLoginEntry(newConfig);
|
||||
}
|
||||
}
|
||||
|
||||
private void parseLoginEntry(
|
||||
Map<String, List<AppConfigurationEntry>> newConfig)
|
||||
throws IOException {
|
||||
|
||||
List<AppConfigurationEntry> configEntries = new LinkedList<>();
|
||||
|
||||
// application name
|
||||
String appName = st.sval;
|
||||
lookahead = nextToken();
|
||||
|
||||
if (debugParser != null) {
|
||||
debugParser.println("\tReading next config entry: " + appName);
|
||||
}
|
||||
|
||||
match("{");
|
||||
|
||||
// get the modules
|
||||
while (peek("}") == false) {
|
||||
// get the module class name
|
||||
String moduleClass = match("module class name");
|
||||
|
||||
// controlFlag (required, optional, etc)
|
||||
LoginModuleControlFlag controlFlag;
|
||||
String sflag = match("controlFlag").toUpperCase(Locale.ENGLISH);
|
||||
switch (sflag) {
|
||||
case "REQUIRED":
|
||||
controlFlag = LoginModuleControlFlag.REQUIRED;
|
||||
break;
|
||||
case "REQUISITE":
|
||||
controlFlag = LoginModuleControlFlag.REQUISITE;
|
||||
break;
|
||||
case "SUFFICIENT":
|
||||
controlFlag = LoginModuleControlFlag.SUFFICIENT;
|
||||
break;
|
||||
case "OPTIONAL":
|
||||
controlFlag = LoginModuleControlFlag.OPTIONAL;
|
||||
break;
|
||||
default:
|
||||
throw ioException(
|
||||
"Configuration.Error.Invalid.control.flag.flag",
|
||||
sflag);
|
||||
}
|
||||
|
||||
// get the args
|
||||
Map<String, String> options = new HashMap<>();
|
||||
while (peek(";") == false) {
|
||||
String key = match("option key");
|
||||
match("=");
|
||||
try {
|
||||
options.put(key, expand(match("option value")));
|
||||
} catch (PropertyExpander.ExpandException peee) {
|
||||
throw new IOException(peee.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
lookahead = nextToken();
|
||||
|
||||
// create the new element
|
||||
if (debugParser != null) {
|
||||
debugParser.println("\t\t" + moduleClass + ", " + sflag);
|
||||
for (String key : options.keySet()) {
|
||||
debugParser.println("\t\t\t" + key +
|
||||
"=" + options.get(key));
|
||||
}
|
||||
}
|
||||
configEntries.add(new AppConfigurationEntry(moduleClass,
|
||||
controlFlag,
|
||||
options));
|
||||
}
|
||||
|
||||
match("}");
|
||||
match(";");
|
||||
|
||||
// add this configuration entry
|
||||
if (newConfig.containsKey(appName)) {
|
||||
throw ioException(
|
||||
"Configuration.Error.Can.not.specify.multiple.entries.for.appName",
|
||||
appName);
|
||||
}
|
||||
newConfig.put(appName, configEntries);
|
||||
}
|
||||
|
||||
private String match(String expect) throws IOException {
|
||||
|
||||
String value = null;
|
||||
|
||||
switch(lookahead) {
|
||||
case StreamTokenizer.TT_EOF:
|
||||
throw ioException(
|
||||
"Configuration.Error.expected.expect.read.end.of.file.",
|
||||
expect);
|
||||
|
||||
case '"':
|
||||
case StreamTokenizer.TT_WORD:
|
||||
if (expect.equalsIgnoreCase("module class name") ||
|
||||
expect.equalsIgnoreCase("controlFlag") ||
|
||||
expect.equalsIgnoreCase("option key") ||
|
||||
expect.equalsIgnoreCase("option value")) {
|
||||
value = st.sval;
|
||||
lookahead = nextToken();
|
||||
} else {
|
||||
throw ioException(
|
||||
"Configuration.Error.Line.line.expected.expect.found.value.",
|
||||
new Integer(linenum), expect, st.sval);
|
||||
}
|
||||
break;
|
||||
|
||||
case '{':
|
||||
if (expect.equalsIgnoreCase("{")) {
|
||||
lookahead = nextToken();
|
||||
} else {
|
||||
throw ioException(
|
||||
"Configuration.Error.Line.line.expected.expect.",
|
||||
new Integer(linenum), expect, st.sval);
|
||||
}
|
||||
break;
|
||||
|
||||
case ';':
|
||||
if (expect.equalsIgnoreCase(";")) {
|
||||
lookahead = nextToken();
|
||||
} else {
|
||||
throw ioException(
|
||||
"Configuration.Error.Line.line.expected.expect.",
|
||||
new Integer(linenum), expect, st.sval);
|
||||
}
|
||||
break;
|
||||
|
||||
case '}':
|
||||
if (expect.equalsIgnoreCase("}")) {
|
||||
lookahead = nextToken();
|
||||
} else {
|
||||
throw ioException(
|
||||
"Configuration.Error.Line.line.expected.expect.",
|
||||
new Integer(linenum), expect, st.sval);
|
||||
}
|
||||
break;
|
||||
|
||||
case '=':
|
||||
if (expect.equalsIgnoreCase("=")) {
|
||||
lookahead = nextToken();
|
||||
} else {
|
||||
throw ioException(
|
||||
"Configuration.Error.Line.line.expected.expect.",
|
||||
new Integer(linenum), expect, st.sval);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw ioException(
|
||||
"Configuration.Error.Line.line.expected.expect.found.value.",
|
||||
new Integer(linenum), expect, st.sval);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private boolean peek(String expect) {
|
||||
switch (lookahead) {
|
||||
case ',':
|
||||
return expect.equalsIgnoreCase(",");
|
||||
case ';':
|
||||
return expect.equalsIgnoreCase(";");
|
||||
case '{':
|
||||
return expect.equalsIgnoreCase("{");
|
||||
case '}':
|
||||
return expect.equalsIgnoreCase("}");
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private int nextToken() throws IOException {
|
||||
int tok;
|
||||
while ((tok = st.nextToken()) == StreamTokenizer.TT_EOL) {
|
||||
linenum++;
|
||||
}
|
||||
return tok;
|
||||
}
|
||||
|
||||
private InputStream getInputStream(URL url) throws IOException {
|
||||
if ("file".equalsIgnoreCase(url.getProtocol())) {
|
||||
// Compatibility notes:
|
||||
//
|
||||
// Code changed from
|
||||
// String path = url.getFile().replace('/', File.separatorChar);
|
||||
// return new FileInputStream(path);
|
||||
//
|
||||
// The original implementation would search for "/tmp/a%20b"
|
||||
// when url is "file:///tmp/a%20b". This is incorrect. The
|
||||
// current codes fix this bug and searches for "/tmp/a b".
|
||||
// For compatibility reasons, when the file "/tmp/a b" does
|
||||
// not exist, the file named "/tmp/a%20b" will be tried.
|
||||
//
|
||||
// This also means that if both file exists, the behavior of
|
||||
// this method is changed, and the current codes choose the
|
||||
// correct one.
|
||||
try {
|
||||
return url.openStream();
|
||||
} catch (Exception e) {
|
||||
String file = url.getPath();
|
||||
if (url.getHost().length() > 0) { // For Windows UNC
|
||||
file = "//" + url.getHost() + file;
|
||||
}
|
||||
if (debugConfig != null) {
|
||||
debugConfig.println("cannot read " + url +
|
||||
", try " + file);
|
||||
}
|
||||
return new FileInputStream(file);
|
||||
}
|
||||
} else {
|
||||
return url.openStream();
|
||||
}
|
||||
}
|
||||
|
||||
private String expand(String value)
|
||||
throws PropertyExpander.ExpandException, IOException {
|
||||
|
||||
if (value.isEmpty()) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (!expandProp) {
|
||||
return value;
|
||||
}
|
||||
String s = PropertyExpander.expand(value);
|
||||
if (s == null || s.length() == 0) {
|
||||
throw ioException(
|
||||
"Configuration.Error.Line.line.system.property.value.expanded.to.empty.value",
|
||||
new Integer(linenum), value);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
private IOException ioException(String resourceKey, Object... args) {
|
||||
MessageFormat form = new MessageFormat(ResourcesMgr.getString
|
||||
(resourceKey, "sun.security.util.AuthResources"));
|
||||
return new IOException(form.format(args));
|
||||
}
|
||||
}
|
||||
}
|
||||
558
jdkSrc/jdk8/sun/security/provider/DSA.java
Normal file
558
jdkSrc/jdk8/sun/security/provider/DSA.java
Normal file
@@ -0,0 +1,558 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.interfaces.*;
|
||||
import java.security.spec.*;
|
||||
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.util.DerValue;
|
||||
import sun.security.util.DerInputStream;
|
||||
import sun.security.util.DerOutputStream;
|
||||
import sun.security.x509.AlgIdDSA;
|
||||
import sun.security.jca.JCAUtil;
|
||||
|
||||
/**
|
||||
* The Digital Signature Standard (using the Digital Signature
|
||||
* Algorithm), as described in fips186-3 of the National Instute of
|
||||
* Standards and Technology (NIST), using SHA digest algorithms
|
||||
* from FIPS180-3.
|
||||
*
|
||||
* This file contains both the signature implementation for the
|
||||
* commonly used SHA1withDSA (DSS), SHA224withDSA, SHA256withDSA,
|
||||
* as well as RawDSA, used by TLS among others. RawDSA expects
|
||||
* the 20 byte SHA-1 digest as input via update rather than the
|
||||
* original data like other signature implementations.
|
||||
*
|
||||
* @author Benjamin Renaud
|
||||
*
|
||||
* @since 1.1
|
||||
*
|
||||
* @see DSAPublicKey
|
||||
* @see DSAPrivateKey
|
||||
*/
|
||||
abstract class DSA extends SignatureSpi {
|
||||
|
||||
/* Are we debugging? */
|
||||
private static final boolean debug = false;
|
||||
|
||||
/* The number of bits used in exponent blinding */
|
||||
private static final int BLINDING_BITS = 7;
|
||||
|
||||
/* The constant component of the exponent blinding value */
|
||||
private static final BigInteger BLINDING_CONSTANT =
|
||||
BigInteger.valueOf(1 << BLINDING_BITS);
|
||||
|
||||
/* The parameter object */
|
||||
private DSAParams params;
|
||||
|
||||
/* algorithm parameters */
|
||||
private BigInteger presetP, presetQ, presetG;
|
||||
|
||||
/* The public key, if any */
|
||||
private BigInteger presetY;
|
||||
|
||||
/* The private key, if any */
|
||||
private BigInteger presetX;
|
||||
|
||||
/* The RNG used to output a seed for generating k */
|
||||
private SecureRandom signingRandom;
|
||||
|
||||
/* The message digest object used */
|
||||
private final MessageDigest md;
|
||||
|
||||
/**
|
||||
* Construct a blank DSA object. It must be
|
||||
* initialized before being usable for signing or verifying.
|
||||
*/
|
||||
DSA(MessageDigest md) {
|
||||
super();
|
||||
this.md = md;
|
||||
}
|
||||
|
||||
private static void checkKey(DSAParams params, int digestLen, String mdAlgo)
|
||||
throws InvalidKeyException {
|
||||
// FIPS186-3 states in sec4.2 that a hash function which provides
|
||||
// a lower security strength than the (L, N) pair ordinarily should
|
||||
// not be used.
|
||||
int valueN = params.getQ().bitLength();
|
||||
if (valueN > digestLen) {
|
||||
throw new InvalidKeyException("The security strength of " +
|
||||
mdAlgo + " digest algorithm is not sufficient for this key size");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the DSA object with a DSA private key.
|
||||
*
|
||||
* @param privateKey the DSA private key
|
||||
*
|
||||
* @exception InvalidKeyException if the key is not a valid DSA private
|
||||
* key.
|
||||
*/
|
||||
protected void engineInitSign(PrivateKey privateKey)
|
||||
throws InvalidKeyException {
|
||||
if (!(privateKey instanceof java.security.interfaces.DSAPrivateKey)) {
|
||||
throw new InvalidKeyException("not a DSA private key: " +
|
||||
privateKey);
|
||||
}
|
||||
|
||||
java.security.interfaces.DSAPrivateKey priv =
|
||||
(java.security.interfaces.DSAPrivateKey)privateKey;
|
||||
|
||||
// check for algorithm specific constraints before doing initialization
|
||||
DSAParams params = priv.getParams();
|
||||
if (params == null) {
|
||||
throw new InvalidKeyException("DSA private key lacks parameters");
|
||||
}
|
||||
|
||||
// check key size against hash output size for signing
|
||||
// skip this check for verification to minimize impact on existing apps
|
||||
if (md.getAlgorithm() != "NullDigest20") {
|
||||
checkKey(params, md.getDigestLength()*8, md.getAlgorithm());
|
||||
}
|
||||
|
||||
this.params = params;
|
||||
this.presetX = priv.getX();
|
||||
this.presetY = null;
|
||||
this.presetP = params.getP();
|
||||
this.presetQ = params.getQ();
|
||||
this.presetG = params.getG();
|
||||
this.md.reset();
|
||||
}
|
||||
/**
|
||||
* Initialize the DSA object with a DSA public key.
|
||||
*
|
||||
* @param publicKey the DSA public key.
|
||||
*
|
||||
* @exception InvalidKeyException if the key is not a valid DSA public
|
||||
* key.
|
||||
*/
|
||||
protected void engineInitVerify(PublicKey publicKey)
|
||||
throws InvalidKeyException {
|
||||
if (!(publicKey instanceof java.security.interfaces.DSAPublicKey)) {
|
||||
throw new InvalidKeyException("not a DSA public key: " +
|
||||
publicKey);
|
||||
}
|
||||
java.security.interfaces.DSAPublicKey pub =
|
||||
(java.security.interfaces.DSAPublicKey)publicKey;
|
||||
|
||||
// check for algorithm specific constraints before doing initialization
|
||||
DSAParams params = pub.getParams();
|
||||
if (params == null) {
|
||||
throw new InvalidKeyException("DSA public key lacks parameters");
|
||||
}
|
||||
this.params = params;
|
||||
this.presetY = pub.getY();
|
||||
this.presetX = null;
|
||||
this.presetP = params.getP();
|
||||
this.presetQ = params.getQ();
|
||||
this.presetG = params.getG();
|
||||
this.md.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a byte to be signed or verified.
|
||||
*/
|
||||
protected void engineUpdate(byte b) {
|
||||
md.update(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an array of bytes to be signed or verified.
|
||||
*/
|
||||
protected void engineUpdate(byte[] data, int off, int len) {
|
||||
md.update(data, off, len);
|
||||
}
|
||||
|
||||
protected void engineUpdate(ByteBuffer b) {
|
||||
md.update(b);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sign all the data thus far updated. The signature is formatted
|
||||
* according to the Canonical Encoding Rules, returned as a DER
|
||||
* sequence of Integer, r and s.
|
||||
*
|
||||
* @return a signature block formatted according to the Canonical
|
||||
* Encoding Rules.
|
||||
*
|
||||
* @exception SignatureException if the signature object was not
|
||||
* properly initialized, or if another exception occurs.
|
||||
*
|
||||
* @see sun.security.DSA#engineUpdate
|
||||
* @see sun.security.DSA#engineVerify
|
||||
*/
|
||||
protected byte[] engineSign() throws SignatureException {
|
||||
BigInteger k = generateK(presetQ);
|
||||
BigInteger r = generateR(presetP, presetQ, presetG, k);
|
||||
BigInteger s = generateS(presetX, presetQ, r, k);
|
||||
|
||||
try {
|
||||
DerOutputStream outseq = new DerOutputStream(100);
|
||||
outseq.putInteger(r);
|
||||
outseq.putInteger(s);
|
||||
DerValue result = new DerValue(DerValue.tag_Sequence,
|
||||
outseq.toByteArray());
|
||||
|
||||
return result.toByteArray();
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new SignatureException("error encoding signature");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify all the data thus far updated.
|
||||
*
|
||||
* @param signature the alledged signature, encoded using the
|
||||
* Canonical Encoding Rules, as a sequence of integers, r and s.
|
||||
*
|
||||
* @exception SignatureException if the signature object was not
|
||||
* properly initialized, or if another exception occurs.
|
||||
*
|
||||
* @see sun.security.DSA#engineUpdate
|
||||
* @see sun.security.DSA#engineSign
|
||||
*/
|
||||
protected boolean engineVerify(byte[] signature)
|
||||
throws SignatureException {
|
||||
return engineVerify(signature, 0, signature.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify all the data thus far updated.
|
||||
*
|
||||
* @param signature the alledged signature, encoded using the
|
||||
* Canonical Encoding Rules, as a sequence of integers, r and s.
|
||||
*
|
||||
* @param offset the offset to start from in the array of bytes.
|
||||
*
|
||||
* @param length the number of bytes to use, starting at offset.
|
||||
*
|
||||
* @exception SignatureException if the signature object was not
|
||||
* properly initialized, or if another exception occurs.
|
||||
*
|
||||
* @see sun.security.DSA#engineUpdate
|
||||
* @see sun.security.DSA#engineSign
|
||||
*/
|
||||
protected boolean engineVerify(byte[] signature, int offset, int length)
|
||||
throws SignatureException {
|
||||
|
||||
BigInteger r = null;
|
||||
BigInteger s = null;
|
||||
// first decode the signature.
|
||||
try {
|
||||
// Enforce strict DER checking for signatures
|
||||
DerInputStream in =
|
||||
new DerInputStream(signature, offset, length, false);
|
||||
DerValue[] values = in.getSequence(2);
|
||||
|
||||
// check number of components in the read sequence
|
||||
// and trailing data
|
||||
if ((values.length != 2) || (in.available() != 0)) {
|
||||
throw new IOException("Invalid encoding for signature");
|
||||
}
|
||||
r = values[0].getBigInteger();
|
||||
s = values[1].getBigInteger();
|
||||
} catch (IOException e) {
|
||||
throw new SignatureException("Invalid encoding for signature", e);
|
||||
}
|
||||
|
||||
// some implementations do not correctly encode values in the ASN.1
|
||||
// 2's complement format. force r and s to be positive in order to
|
||||
// to validate those signatures
|
||||
if (r.signum() < 0) {
|
||||
r = new BigInteger(1, r.toByteArray());
|
||||
}
|
||||
if (s.signum() < 0) {
|
||||
s = new BigInteger(1, s.toByteArray());
|
||||
}
|
||||
|
||||
if ((r.compareTo(presetQ) == -1) && (s.compareTo(presetQ) == -1)
|
||||
&& r.signum() > 0 && s.signum() > 0) {
|
||||
BigInteger w = generateW(presetP, presetQ, presetG, s);
|
||||
BigInteger v = generateV(presetY, presetP, presetQ, presetG, w, r);
|
||||
return v.equals(r);
|
||||
} else {
|
||||
throw new SignatureException("invalid signature: out of range values");
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
protected void engineSetParameter(String key, Object param) {
|
||||
throw new InvalidParameterException("No parameter accepted");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineSetParameter(AlgorithmParameterSpec params)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
if (params != null) {
|
||||
throw new InvalidAlgorithmParameterException("No parameter accepted");
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
protected Object engineGetParameter(String key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AlgorithmParameters engineGetParameters() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private BigInteger generateR(BigInteger p, BigInteger q, BigInteger g,
|
||||
BigInteger k) {
|
||||
|
||||
// exponent blinding to hide information from timing channel
|
||||
SecureRandom random = getSigningRandom();
|
||||
// start with a random blinding component
|
||||
BigInteger blindingValue = new BigInteger(BLINDING_BITS, random);
|
||||
// add the fixed blinding component
|
||||
blindingValue = blindingValue.add(BLINDING_CONSTANT);
|
||||
// replace k with a blinded value that is congruent (mod q)
|
||||
k = k.add(q.multiply(blindingValue));
|
||||
|
||||
BigInteger temp = g.modPow(k, p);
|
||||
return temp.mod(q);
|
||||
}
|
||||
|
||||
private BigInteger generateS(BigInteger x, BigInteger q,
|
||||
BigInteger r, BigInteger k) throws SignatureException {
|
||||
|
||||
byte[] s2;
|
||||
try {
|
||||
s2 = md.digest();
|
||||
} catch (RuntimeException re) {
|
||||
// Only for RawDSA due to its 20-byte length restriction
|
||||
throw new SignatureException(re.getMessage());
|
||||
}
|
||||
// get the leftmost min(N, outLen) bits of the digest value
|
||||
int nBytes = q.bitLength()/8;
|
||||
if (nBytes < s2.length) {
|
||||
s2 = Arrays.copyOfRange(s2, 0, nBytes);
|
||||
}
|
||||
BigInteger z = new BigInteger(1, s2);
|
||||
BigInteger k1 = k.modInverse(q);
|
||||
|
||||
return x.multiply(r).add(z).multiply(k1).mod(q);
|
||||
}
|
||||
|
||||
private BigInteger generateW(BigInteger p, BigInteger q,
|
||||
BigInteger g, BigInteger s) {
|
||||
return s.modInverse(q);
|
||||
}
|
||||
|
||||
private BigInteger generateV(BigInteger y, BigInteger p,
|
||||
BigInteger q, BigInteger g, BigInteger w, BigInteger r)
|
||||
throws SignatureException {
|
||||
|
||||
byte[] s2;
|
||||
try {
|
||||
s2 = md.digest();
|
||||
} catch (RuntimeException re) {
|
||||
// Only for RawDSA due to its 20-byte length restriction
|
||||
throw new SignatureException(re.getMessage());
|
||||
}
|
||||
// get the leftmost min(N, outLen) bits of the digest value
|
||||
int nBytes = q.bitLength()/8;
|
||||
if (nBytes < s2.length) {
|
||||
s2 = Arrays.copyOfRange(s2, 0, nBytes);
|
||||
}
|
||||
BigInteger z = new BigInteger(1, s2);
|
||||
|
||||
BigInteger u1 = z.multiply(w).mod(q);
|
||||
BigInteger u2 = (r.multiply(w)).mod(q);
|
||||
|
||||
BigInteger t1 = g.modPow(u1,p);
|
||||
BigInteger t2 = y.modPow(u2,p);
|
||||
BigInteger t3 = t1.multiply(t2);
|
||||
BigInteger t5 = t3.mod(p);
|
||||
return t5.mod(q);
|
||||
}
|
||||
|
||||
protected BigInteger generateK(BigInteger q) {
|
||||
// Implementation defined in FIPS 186-4 AppendixB.2.1.
|
||||
SecureRandom random = getSigningRandom();
|
||||
byte[] kValue = new byte[(q.bitLength() + 7)/8 + 8];
|
||||
|
||||
random.nextBytes(kValue);
|
||||
return new BigInteger(1, kValue).mod(
|
||||
q.subtract(BigInteger.ONE)).add(BigInteger.ONE);
|
||||
}
|
||||
|
||||
// Use the application-specified SecureRandom Object if provided.
|
||||
// Otherwise, use our default SecureRandom Object.
|
||||
protected SecureRandom getSigningRandom() {
|
||||
if (signingRandom == null) {
|
||||
if (appRandom != null) {
|
||||
signingRandom = appRandom;
|
||||
} else {
|
||||
signingRandom = JCAUtil.getSecureRandom();
|
||||
}
|
||||
}
|
||||
return signingRandom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a human readable rendition of the engine.
|
||||
*/
|
||||
public String toString() {
|
||||
String printable = "DSA Signature";
|
||||
if (presetP != null && presetQ != null && presetG != null) {
|
||||
printable += "\n\tp: " + Debug.toHexString(presetP);
|
||||
printable += "\n\tq: " + Debug.toHexString(presetQ);
|
||||
printable += "\n\tg: " + Debug.toHexString(presetG);
|
||||
} else {
|
||||
printable += "\n\t P, Q or G not initialized.";
|
||||
}
|
||||
if (presetY != null) {
|
||||
printable += "\n\ty: " + Debug.toHexString(presetY);
|
||||
}
|
||||
if (presetY == null && presetX == null) {
|
||||
printable += "\n\tUNINIIALIZED";
|
||||
}
|
||||
return printable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard SHA224withDSA implementation as defined in FIPS186-3.
|
||||
*/
|
||||
public static final class SHA224withDSA extends DSA {
|
||||
public SHA224withDSA() throws NoSuchAlgorithmException {
|
||||
super(MessageDigest.getInstance("SHA-224"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard SHA256withDSA implementation as defined in FIPS186-3.
|
||||
*/
|
||||
public static final class SHA256withDSA extends DSA {
|
||||
public SHA256withDSA() throws NoSuchAlgorithmException {
|
||||
super(MessageDigest.getInstance("SHA-256"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard SHA1withDSA implementation.
|
||||
*/
|
||||
public static final class SHA1withDSA extends DSA {
|
||||
public SHA1withDSA() throws NoSuchAlgorithmException {
|
||||
super(MessageDigest.getInstance("SHA-1"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RawDSA implementation.
|
||||
*
|
||||
* RawDSA requires the data to be exactly 20 bytes long. If it is
|
||||
* not, a SignatureException is thrown when sign()/verify() is called
|
||||
* per JCA spec.
|
||||
*/
|
||||
public static final class RawDSA extends DSA {
|
||||
// Internal special-purpose MessageDigest impl for RawDSA
|
||||
// Only override whatever methods used
|
||||
// NOTE: no clone support
|
||||
public static final class NullDigest20 extends MessageDigest {
|
||||
// 20 byte digest buffer
|
||||
private final byte[] digestBuffer = new byte[20];
|
||||
|
||||
// offset into the buffer; use Integer.MAX_VALUE to indicate
|
||||
// out-of-bound condition
|
||||
private int ofs = 0;
|
||||
|
||||
protected NullDigest20() {
|
||||
super("NullDigest20");
|
||||
}
|
||||
protected void engineUpdate(byte input) {
|
||||
if (ofs == digestBuffer.length) {
|
||||
ofs = Integer.MAX_VALUE;
|
||||
} else {
|
||||
digestBuffer[ofs++] = input;
|
||||
}
|
||||
}
|
||||
protected void engineUpdate(byte[] input, int offset, int len) {
|
||||
if (len > (digestBuffer.length - ofs)) {
|
||||
ofs = Integer.MAX_VALUE;
|
||||
} else {
|
||||
System.arraycopy(input, offset, digestBuffer, ofs, len);
|
||||
ofs += len;
|
||||
}
|
||||
}
|
||||
protected final void engineUpdate(ByteBuffer input) {
|
||||
int inputLen = input.remaining();
|
||||
if (inputLen > (digestBuffer.length - ofs)) {
|
||||
ofs = Integer.MAX_VALUE;
|
||||
} else {
|
||||
input.get(digestBuffer, ofs, inputLen);
|
||||
ofs += inputLen;
|
||||
}
|
||||
}
|
||||
protected byte[] engineDigest() throws RuntimeException {
|
||||
if (ofs != digestBuffer.length) {
|
||||
throw new RuntimeException
|
||||
("Data for RawDSA must be exactly 20 bytes long");
|
||||
}
|
||||
reset();
|
||||
return digestBuffer;
|
||||
}
|
||||
protected int engineDigest(byte[] buf, int offset, int len)
|
||||
throws DigestException {
|
||||
if (ofs != digestBuffer.length) {
|
||||
throw new DigestException
|
||||
("Data for RawDSA must be exactly 20 bytes long");
|
||||
}
|
||||
if (len < digestBuffer.length) {
|
||||
throw new DigestException
|
||||
("Output buffer too small; must be at least 20 bytes");
|
||||
}
|
||||
System.arraycopy(digestBuffer, 0, buf, offset, digestBuffer.length);
|
||||
reset();
|
||||
return digestBuffer.length;
|
||||
}
|
||||
|
||||
protected void engineReset() {
|
||||
ofs = 0;
|
||||
}
|
||||
protected final int engineGetDigestLength() {
|
||||
return digestBuffer.length;
|
||||
}
|
||||
}
|
||||
|
||||
public RawDSA() throws NoSuchAlgorithmException {
|
||||
super(new NullDigest20());
|
||||
}
|
||||
}
|
||||
}
|
||||
288
jdkSrc/jdk8/sun/security/provider/DSAKeyFactory.java
Normal file
288
jdkSrc/jdk8/sun/security/provider/DSAKeyFactory.java
Normal file
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.security.Key;
|
||||
import java.security.PublicKey;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.KeyFactorySpi;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.AccessController;
|
||||
import java.security.interfaces.DSAParams;
|
||||
import java.security.spec.DSAPublicKeySpec;
|
||||
import java.security.spec.DSAPrivateKeySpec;
|
||||
import java.security.spec.KeySpec;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
* This class implements the DSA key factory of the Sun provider.
|
||||
*
|
||||
* @author Jan Luehe
|
||||
*
|
||||
*
|
||||
* @since 1.2
|
||||
*/
|
||||
|
||||
public class DSAKeyFactory extends KeyFactorySpi {
|
||||
|
||||
// package private for DSAKeyPairGenerator
|
||||
static final boolean SERIAL_INTEROP;
|
||||
private static final String SERIAL_PROP = "sun.security.key.serial.interop";
|
||||
|
||||
static {
|
||||
|
||||
/**
|
||||
* Check to see if we need to maintain interoperability for serialized
|
||||
* keys between JDK 5.0 -> JDK 1.4. In other words, determine whether
|
||||
* a key object serialized in JDK 5.0 must be deserializable in
|
||||
* JDK 1.4.
|
||||
*
|
||||
* If true, then we generate sun.security.provider.DSAPublicKey.
|
||||
* If false, then we generate sun.security.provider.DSAPublicKeyImpl.
|
||||
*
|
||||
* By default this is false.
|
||||
* This incompatibility was introduced by 4532506.
|
||||
*/
|
||||
String prop = AccessController.doPrivileged
|
||||
(new GetPropertyAction(SERIAL_PROP, null));
|
||||
SERIAL_INTEROP = "true".equalsIgnoreCase(prop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a public key object from the provided key specification
|
||||
* (key material).
|
||||
*
|
||||
* @param keySpec the specification (key material) of the public key
|
||||
*
|
||||
* @return the public key
|
||||
*
|
||||
* @exception InvalidKeySpecException if the given key specification
|
||||
* is inappropriate for this key factory to produce a public key.
|
||||
*/
|
||||
protected PublicKey engineGeneratePublic(KeySpec keySpec)
|
||||
throws InvalidKeySpecException {
|
||||
try {
|
||||
if (keySpec instanceof DSAPublicKeySpec) {
|
||||
DSAPublicKeySpec dsaPubKeySpec = (DSAPublicKeySpec)keySpec;
|
||||
if (SERIAL_INTEROP) {
|
||||
return new DSAPublicKey(dsaPubKeySpec.getY(),
|
||||
dsaPubKeySpec.getP(),
|
||||
dsaPubKeySpec.getQ(),
|
||||
dsaPubKeySpec.getG());
|
||||
} else {
|
||||
return new DSAPublicKeyImpl(dsaPubKeySpec.getY(),
|
||||
dsaPubKeySpec.getP(),
|
||||
dsaPubKeySpec.getQ(),
|
||||
dsaPubKeySpec.getG());
|
||||
}
|
||||
} else if (keySpec instanceof X509EncodedKeySpec) {
|
||||
if (SERIAL_INTEROP) {
|
||||
return new DSAPublicKey
|
||||
(((X509EncodedKeySpec)keySpec).getEncoded());
|
||||
} else {
|
||||
return new DSAPublicKeyImpl
|
||||
(((X509EncodedKeySpec)keySpec).getEncoded());
|
||||
}
|
||||
} else {
|
||||
throw new InvalidKeySpecException
|
||||
("Inappropriate key specification");
|
||||
}
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new InvalidKeySpecException
|
||||
("Inappropriate key specification: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a private key object from the provided key specification
|
||||
* (key material).
|
||||
*
|
||||
* @param keySpec the specification (key material) of the private key
|
||||
*
|
||||
* @return the private key
|
||||
*
|
||||
* @exception InvalidKeySpecException if the given key specification
|
||||
* is inappropriate for this key factory to produce a private key.
|
||||
*/
|
||||
protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
|
||||
throws InvalidKeySpecException {
|
||||
try {
|
||||
if (keySpec instanceof DSAPrivateKeySpec) {
|
||||
DSAPrivateKeySpec dsaPrivKeySpec = (DSAPrivateKeySpec)keySpec;
|
||||
return new DSAPrivateKey(dsaPrivKeySpec.getX(),
|
||||
dsaPrivKeySpec.getP(),
|
||||
dsaPrivKeySpec.getQ(),
|
||||
dsaPrivKeySpec.getG());
|
||||
|
||||
} else if (keySpec instanceof PKCS8EncodedKeySpec) {
|
||||
return new DSAPrivateKey
|
||||
(((PKCS8EncodedKeySpec)keySpec).getEncoded());
|
||||
|
||||
} else {
|
||||
throw new InvalidKeySpecException
|
||||
("Inappropriate key specification");
|
||||
}
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new InvalidKeySpecException
|
||||
("Inappropriate key specification: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specification (key material) of the given key object
|
||||
* in the requested format.
|
||||
*
|
||||
* @param key the key
|
||||
*
|
||||
* @param keySpec the requested format in which the key material shall be
|
||||
* returned
|
||||
*
|
||||
* @return the underlying key specification (key material) in the
|
||||
* requested format
|
||||
*
|
||||
* @exception InvalidKeySpecException if the requested key specification is
|
||||
* inappropriate for the given key, or the given key cannot be processed
|
||||
* (e.g., the given key has an unrecognized algorithm or format).
|
||||
*/
|
||||
protected <T extends KeySpec>
|
||||
T engineGetKeySpec(Key key, Class<T> keySpec)
|
||||
throws InvalidKeySpecException {
|
||||
|
||||
DSAParams params;
|
||||
|
||||
try {
|
||||
|
||||
if (key instanceof java.security.interfaces.DSAPublicKey) {
|
||||
|
||||
// Determine valid key specs
|
||||
Class<?> dsaPubKeySpec = Class.forName
|
||||
("java.security.spec.DSAPublicKeySpec");
|
||||
Class<?> x509KeySpec = Class.forName
|
||||
("java.security.spec.X509EncodedKeySpec");
|
||||
|
||||
if (keySpec.isAssignableFrom(dsaPubKeySpec)) {
|
||||
java.security.interfaces.DSAPublicKey dsaPubKey
|
||||
= (java.security.interfaces.DSAPublicKey)key;
|
||||
params = dsaPubKey.getParams();
|
||||
return keySpec.cast(new DSAPublicKeySpec(dsaPubKey.getY(),
|
||||
params.getP(),
|
||||
params.getQ(),
|
||||
params.getG()));
|
||||
|
||||
} else if (keySpec.isAssignableFrom(x509KeySpec)) {
|
||||
return keySpec.cast(new X509EncodedKeySpec(key.getEncoded()));
|
||||
|
||||
} else {
|
||||
throw new InvalidKeySpecException
|
||||
("Inappropriate key specification");
|
||||
}
|
||||
|
||||
} else if (key instanceof java.security.interfaces.DSAPrivateKey) {
|
||||
|
||||
// Determine valid key specs
|
||||
Class<?> dsaPrivKeySpec = Class.forName
|
||||
("java.security.spec.DSAPrivateKeySpec");
|
||||
Class<?> pkcs8KeySpec = Class.forName
|
||||
("java.security.spec.PKCS8EncodedKeySpec");
|
||||
|
||||
if (keySpec.isAssignableFrom(dsaPrivKeySpec)) {
|
||||
java.security.interfaces.DSAPrivateKey dsaPrivKey
|
||||
= (java.security.interfaces.DSAPrivateKey)key;
|
||||
params = dsaPrivKey.getParams();
|
||||
return keySpec.cast(new DSAPrivateKeySpec(dsaPrivKey.getX(),
|
||||
params.getP(),
|
||||
params.getQ(),
|
||||
params.getG()));
|
||||
|
||||
} else if (keySpec.isAssignableFrom(pkcs8KeySpec)) {
|
||||
return keySpec.cast(new PKCS8EncodedKeySpec(key.getEncoded()));
|
||||
|
||||
} else {
|
||||
throw new InvalidKeySpecException
|
||||
("Inappropriate key specification");
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new InvalidKeySpecException("Inappropriate key type");
|
||||
}
|
||||
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new InvalidKeySpecException
|
||||
("Unsupported key specification: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a key object, whose provider may be unknown or potentially
|
||||
* untrusted, into a corresponding key object of this key factory.
|
||||
*
|
||||
* @param key the key whose provider is unknown or untrusted
|
||||
*
|
||||
* @return the translated key
|
||||
*
|
||||
* @exception InvalidKeyException if the given key cannot be processed by
|
||||
* this key factory.
|
||||
*/
|
||||
protected Key engineTranslateKey(Key key) throws InvalidKeyException {
|
||||
|
||||
try {
|
||||
|
||||
if (key instanceof java.security.interfaces.DSAPublicKey) {
|
||||
// Check if key originates from this factory
|
||||
if (key instanceof sun.security.provider.DSAPublicKey) {
|
||||
return key;
|
||||
}
|
||||
// Convert key to spec
|
||||
DSAPublicKeySpec dsaPubKeySpec
|
||||
= engineGetKeySpec(key, DSAPublicKeySpec.class);
|
||||
// Create key from spec, and return it
|
||||
return engineGeneratePublic(dsaPubKeySpec);
|
||||
|
||||
} else if (key instanceof java.security.interfaces.DSAPrivateKey) {
|
||||
// Check if key originates from this factory
|
||||
if (key instanceof sun.security.provider.DSAPrivateKey) {
|
||||
return key;
|
||||
}
|
||||
// Convert key to spec
|
||||
DSAPrivateKeySpec dsaPrivKeySpec
|
||||
= engineGetKeySpec(key, DSAPrivateKeySpec.class);
|
||||
// Create key from spec, and return it
|
||||
return engineGeneratePrivate(dsaPrivKeySpec);
|
||||
|
||||
} else {
|
||||
throw new InvalidKeyException("Wrong algorithm type");
|
||||
}
|
||||
|
||||
} catch (InvalidKeySpecException e) {
|
||||
throw new InvalidKeyException("Cannot translate key: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
264
jdkSrc/jdk8/sun/security/provider/DSAKeyPairGenerator.java
Normal file
264
jdkSrc/jdk8/sun/security/provider/DSAKeyPairGenerator.java
Normal file
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.interfaces.DSAParams;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.security.spec.InvalidParameterSpecException;
|
||||
import java.security.spec.DSAParameterSpec;
|
||||
|
||||
import sun.security.jca.JCAUtil;
|
||||
import static sun.security.util.SecurityProviderConstants.DEF_DSA_KEY_SIZE;
|
||||
import static sun.security.util.SecurityProviderConstants.getDefDSASubprimeSize;
|
||||
|
||||
/**
|
||||
* This class generates DSA key parameters and public/private key
|
||||
* pairs according to the DSS standard NIST FIPS 186. It uses the
|
||||
* updated version of SHA, SHA-1 as described in FIPS 180-1.
|
||||
*
|
||||
* @author Benjamin Renaud
|
||||
* @author Andreas Sterbenz
|
||||
*
|
||||
*/
|
||||
class DSAKeyPairGenerator extends KeyPairGenerator {
|
||||
|
||||
/* Length for prime P and subPrime Q in bits */
|
||||
private int plen;
|
||||
private int qlen;
|
||||
|
||||
/* whether to force new parameters to be generated for each KeyPair */
|
||||
boolean forceNewParameters;
|
||||
|
||||
/* preset algorithm parameters. */
|
||||
private DSAParameterSpec params;
|
||||
|
||||
/* The source of random bits to use */
|
||||
private SecureRandom random;
|
||||
|
||||
DSAKeyPairGenerator(int defaultKeySize) {
|
||||
super("DSA");
|
||||
initialize(defaultKeySize, null);
|
||||
}
|
||||
|
||||
private static void checkStrength(int sizeP, int sizeQ) {
|
||||
if ((sizeP >= 512) && (sizeP <= 1024) && (sizeP % 64 == 0)
|
||||
&& sizeQ == 160) {
|
||||
// traditional - allow for backward compatibility
|
||||
// L=multiples of 64 and between 512 and 1024 (inclusive)
|
||||
// N=160
|
||||
} else if (sizeP == 2048 && (sizeQ == 224 || sizeQ == 256)) {
|
||||
// L=2048, N=224 or 256
|
||||
} else if (sizeP == 3072 && sizeQ == 256) {
|
||||
// L=3072, N=256
|
||||
} else {
|
||||
throw new InvalidParameterException
|
||||
("Unsupported prime and subprime size combination: " +
|
||||
sizeP + ", " + sizeQ);
|
||||
}
|
||||
}
|
||||
|
||||
public void initialize(int modlen, SecureRandom random) {
|
||||
init(modlen, random, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the DSA object using a parameter object.
|
||||
*
|
||||
* @param params the parameter set to be used to generate
|
||||
* the keys.
|
||||
* @param random the source of randomness for this generator.
|
||||
*
|
||||
* @exception InvalidAlgorithmParameterException if the given parameters
|
||||
* are inappropriate for this key pair generator
|
||||
*/
|
||||
public void initialize(AlgorithmParameterSpec params, SecureRandom random)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
if (!(params instanceof DSAParameterSpec)) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Inappropriate parameter");
|
||||
}
|
||||
init((DSAParameterSpec)params, random, false);
|
||||
}
|
||||
|
||||
void init(int modlen, SecureRandom random, boolean forceNew) {
|
||||
int subPrimeLen = getDefDSASubprimeSize(modlen);
|
||||
checkStrength(modlen, subPrimeLen);
|
||||
this.plen = modlen;
|
||||
this.qlen = subPrimeLen;
|
||||
this.params = null;
|
||||
this.random = random;
|
||||
this.forceNewParameters = forceNew;
|
||||
}
|
||||
|
||||
void init(DSAParameterSpec params, SecureRandom random,
|
||||
boolean forceNew) {
|
||||
int sizeP = params.getP().bitLength();
|
||||
int sizeQ = params.getQ().bitLength();
|
||||
checkStrength(sizeP, sizeQ);
|
||||
this.plen = sizeP;
|
||||
this.qlen = sizeQ;
|
||||
this.params = params;
|
||||
this.random = random;
|
||||
this.forceNewParameters = forceNew;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a pair of keys usable by any JavaSecurity compliant
|
||||
* DSA implementation.
|
||||
*/
|
||||
public KeyPair generateKeyPair() {
|
||||
if (random == null) {
|
||||
random = JCAUtil.getSecureRandom();
|
||||
}
|
||||
DSAParameterSpec spec;
|
||||
try {
|
||||
if (forceNewParameters) {
|
||||
// generate new parameters each time
|
||||
spec = ParameterCache.getNewDSAParameterSpec(plen, qlen, random);
|
||||
} else {
|
||||
if (params == null) {
|
||||
params =
|
||||
ParameterCache.getDSAParameterSpec(plen, qlen, random);
|
||||
}
|
||||
spec = params;
|
||||
}
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new ProviderException(e);
|
||||
}
|
||||
return generateKeyPair(spec.getP(), spec.getQ(), spec.getG(), random);
|
||||
}
|
||||
|
||||
private KeyPair generateKeyPair(BigInteger p, BigInteger q, BigInteger g,
|
||||
SecureRandom random) {
|
||||
|
||||
BigInteger x = generateX(random, q);
|
||||
BigInteger y = generateY(x, p, g);
|
||||
|
||||
try {
|
||||
|
||||
// See the comments in DSAKeyFactory, 4532506, and 6232513.
|
||||
|
||||
DSAPublicKey pub;
|
||||
if (DSAKeyFactory.SERIAL_INTEROP) {
|
||||
pub = new DSAPublicKey(y, p, q, g);
|
||||
} else {
|
||||
pub = new DSAPublicKeyImpl(y, p, q, g);
|
||||
}
|
||||
DSAPrivateKey priv = new DSAPrivateKey(x, p, q, g);
|
||||
|
||||
KeyPair pair = new KeyPair(pub, priv);
|
||||
return pair;
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new ProviderException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the private key component of the key pair using the
|
||||
* provided source of random bits. This method uses the random but
|
||||
* source passed to generate a seed and then calls the seed-based
|
||||
* generateX method.
|
||||
*/
|
||||
private BigInteger generateX(SecureRandom random, BigInteger q) {
|
||||
BigInteger x = null;
|
||||
byte[] temp = new byte[qlen];
|
||||
while (true) {
|
||||
random.nextBytes(temp);
|
||||
x = new BigInteger(1, temp).mod(q);
|
||||
if (x.signum() > 0 && (x.compareTo(q) < 0)) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the public key component y of the key pair.
|
||||
*
|
||||
* @param x the private key component.
|
||||
*
|
||||
* @param p the base parameter.
|
||||
*/
|
||||
BigInteger generateY(BigInteger x, BigInteger p, BigInteger g) {
|
||||
BigInteger y = g.modPow(x, p);
|
||||
return y;
|
||||
}
|
||||
|
||||
public static final class Current extends DSAKeyPairGenerator {
|
||||
public Current() {
|
||||
super(DEF_DSA_KEY_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Legacy extends DSAKeyPairGenerator
|
||||
implements java.security.interfaces.DSAKeyPairGenerator {
|
||||
|
||||
public Legacy() {
|
||||
super(1024);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the DSA key pair generator. If <code>genParams</code>
|
||||
* is false, a set of pre-computed parameters is used.
|
||||
*/
|
||||
@Override
|
||||
public void initialize(int modlen, boolean genParams,
|
||||
SecureRandom random) throws InvalidParameterException {
|
||||
if (genParams) {
|
||||
super.init(modlen, random, true);
|
||||
} else {
|
||||
DSAParameterSpec cachedParams =
|
||||
ParameterCache.getCachedDSAParameterSpec(modlen,
|
||||
getDefDSASubprimeSize(modlen));
|
||||
if (cachedParams == null) {
|
||||
throw new InvalidParameterException
|
||||
("No precomputed parameters for requested modulus" +
|
||||
" size available");
|
||||
}
|
||||
super.init(cachedParams, random, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the DSA object using a DSA parameter object.
|
||||
*
|
||||
* @param params a fully initialized DSA parameter object.
|
||||
*/
|
||||
@Override
|
||||
public void initialize(DSAParams params, SecureRandom random)
|
||||
throws InvalidParameterException {
|
||||
if (params == null) {
|
||||
throw new InvalidParameterException("Params must not be null");
|
||||
}
|
||||
DSAParameterSpec spec = new DSAParameterSpec
|
||||
(params.getP(), params.getQ(), params.getG());
|
||||
super.init(spec, random, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
306
jdkSrc/jdk8/sun/security/provider/DSAParameterGenerator.java
Normal file
306
jdkSrc/jdk8/sun/security/provider/DSAParameterGenerator.java
Normal file
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.AlgorithmParameterGeneratorSpi;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.InvalidParameterException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.ProviderException;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.security.spec.InvalidParameterSpecException;
|
||||
import java.security.spec.DSAParameterSpec;
|
||||
import java.security.spec.DSAGenParameterSpec;
|
||||
|
||||
import static sun.security.util.SecurityProviderConstants.DEF_DSA_KEY_SIZE;
|
||||
import static sun.security.util.SecurityProviderConstants.getDefDSASubprimeSize;
|
||||
|
||||
|
||||
/**
|
||||
* This class generates parameters for the DSA algorithm.
|
||||
*
|
||||
* @author Jan Luehe
|
||||
*
|
||||
*
|
||||
* @see java.security.AlgorithmParameters
|
||||
* @see java.security.spec.AlgorithmParameterSpec
|
||||
* @see DSAParameters
|
||||
*
|
||||
* @since 1.2
|
||||
*/
|
||||
|
||||
public class DSAParameterGenerator extends AlgorithmParameterGeneratorSpi {
|
||||
|
||||
// the length of prime P, subPrime Q, and seed in bits
|
||||
private int valueL = -1;
|
||||
private int valueN = -1;
|
||||
private int seedLen = -1;
|
||||
|
||||
// the source of randomness
|
||||
private SecureRandom random;
|
||||
|
||||
// useful constants
|
||||
private static final BigInteger TWO = BigInteger.valueOf(2);
|
||||
|
||||
public DSAParameterGenerator() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this parameter generator for a certain strength
|
||||
* and source of randomness.
|
||||
*
|
||||
* @param strength the strength (size of prime) in bits
|
||||
* @param random the source of randomness
|
||||
*/
|
||||
@Override
|
||||
protected void engineInit(int strength, SecureRandom random) {
|
||||
if ((strength != 2048) && (strength != 3072) &&
|
||||
((strength < 512) || (strength > 1024) || (strength % 64 != 0))) {
|
||||
throw new InvalidParameterException(
|
||||
"Unexpected strength (size of prime): " + strength +
|
||||
". Prime size should be 512-1024, 2048, or 3072");
|
||||
}
|
||||
this.valueL = strength;
|
||||
this.valueN = getDefDSASubprimeSize(strength);
|
||||
this.seedLen = valueN;
|
||||
this.random = random;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this parameter generator with a set of
|
||||
* algorithm-specific parameter generation values.
|
||||
*
|
||||
* @param genParamSpec the set of algorithm-specific parameter
|
||||
* generation values
|
||||
* @param random the source of randomness
|
||||
*
|
||||
* @exception InvalidAlgorithmParameterException if the given parameter
|
||||
* generation values are inappropriate for this parameter generator
|
||||
*/
|
||||
@Override
|
||||
protected void engineInit(AlgorithmParameterSpec genParamSpec,
|
||||
SecureRandom random) throws InvalidAlgorithmParameterException {
|
||||
if (!(genParamSpec instanceof DSAGenParameterSpec)) {
|
||||
throw new InvalidAlgorithmParameterException("Invalid parameter");
|
||||
}
|
||||
DSAGenParameterSpec dsaGenParams = (DSAGenParameterSpec)genParamSpec;
|
||||
|
||||
// directly initialize using the already validated values
|
||||
this.valueL = dsaGenParams.getPrimePLength();
|
||||
this.valueN = dsaGenParams.getSubprimeQLength();
|
||||
this.seedLen = dsaGenParams.getSeedLength();
|
||||
this.random = random;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the parameters.
|
||||
*
|
||||
* @return the new AlgorithmParameters object
|
||||
*/
|
||||
@Override
|
||||
protected AlgorithmParameters engineGenerateParameters() {
|
||||
AlgorithmParameters algParams = null;
|
||||
try {
|
||||
if (this.random == null) {
|
||||
this.random = new SecureRandom();
|
||||
}
|
||||
if (valueL == -1) {
|
||||
engineInit(DEF_DSA_KEY_SIZE, this.random);
|
||||
}
|
||||
BigInteger[] pAndQ = generatePandQ(this.random, valueL,
|
||||
valueN, seedLen);
|
||||
BigInteger paramP = pAndQ[0];
|
||||
BigInteger paramQ = pAndQ[1];
|
||||
BigInteger paramG = generateG(paramP, paramQ);
|
||||
|
||||
DSAParameterSpec dsaParamSpec =
|
||||
new DSAParameterSpec(paramP, paramQ, paramG);
|
||||
algParams = AlgorithmParameters.getInstance("DSA", "SUN");
|
||||
algParams.init(dsaParamSpec);
|
||||
} catch (InvalidParameterSpecException e) {
|
||||
// this should never happen
|
||||
throw new RuntimeException(e.getMessage());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// this should never happen, because we provide it
|
||||
throw new RuntimeException(e.getMessage());
|
||||
} catch (NoSuchProviderException e) {
|
||||
// this should never happen, because we provide it
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
|
||||
return algParams;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generates the prime and subprime parameters for DSA,
|
||||
* using the provided source of randomness.
|
||||
* This method will generate new seeds until a suitable
|
||||
* seed has been found.
|
||||
*
|
||||
* @param random the source of randomness to generate the
|
||||
* seed
|
||||
* @param valueL the size of <code>p</code>, in bits.
|
||||
* @param valueN the size of <code>q</code>, in bits.
|
||||
* @param seedLen the length of <code>seed</code>, in bits.
|
||||
*
|
||||
* @return an array of BigInteger, with <code>p</code> at index 0 and
|
||||
* <code>q</code> at index 1, the seed at index 2, and the counter value
|
||||
* at index 3.
|
||||
*/
|
||||
private static BigInteger[] generatePandQ(SecureRandom random, int valueL,
|
||||
int valueN, int seedLen) {
|
||||
String hashAlg = null;
|
||||
if (valueN == 160) {
|
||||
hashAlg = "SHA";
|
||||
} else if (valueN == 224) {
|
||||
hashAlg = "SHA-224";
|
||||
} else if (valueN == 256) {
|
||||
hashAlg = "SHA-256";
|
||||
}
|
||||
MessageDigest hashObj = null;
|
||||
try {
|
||||
hashObj = MessageDigest.getInstance(hashAlg);
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
// should never happen
|
||||
nsae.printStackTrace();
|
||||
}
|
||||
|
||||
/* Step 3, 4: Useful variables */
|
||||
int outLen = hashObj.getDigestLength()*8;
|
||||
int n = (valueL - 1) / outLen;
|
||||
int b = (valueL - 1) % outLen;
|
||||
byte[] seedBytes = new byte[seedLen/8];
|
||||
BigInteger twoSl = TWO.pow(seedLen);
|
||||
int primeCertainty = -1;
|
||||
if (valueL <= 1024) {
|
||||
primeCertainty = 80;
|
||||
} else if (valueL == 2048) {
|
||||
primeCertainty = 112;
|
||||
} else if (valueL == 3072) {
|
||||
primeCertainty = 128;
|
||||
}
|
||||
if (primeCertainty < 0) {
|
||||
throw new ProviderException("Invalid valueL: " + valueL);
|
||||
}
|
||||
BigInteger resultP, resultQ, seed = null;
|
||||
int counter;
|
||||
while (true) {
|
||||
do {
|
||||
/* Step 5 */
|
||||
random.nextBytes(seedBytes);
|
||||
seed = new BigInteger(1, seedBytes);
|
||||
|
||||
/* Step 6 */
|
||||
BigInteger U = new BigInteger(1, hashObj.digest(seedBytes)).
|
||||
mod(TWO.pow(valueN - 1));
|
||||
|
||||
/* Step 7 */
|
||||
resultQ = TWO.pow(valueN - 1)
|
||||
.add(U)
|
||||
.add(BigInteger.ONE)
|
||||
.subtract(U.mod(TWO));
|
||||
} while (!resultQ.isProbablePrime(primeCertainty));
|
||||
|
||||
/* Step 10 */
|
||||
BigInteger offset = BigInteger.ONE;
|
||||
/* Step 11 */
|
||||
for (counter = 0; counter < 4*valueL; counter++) {
|
||||
BigInteger V[] = new BigInteger[n + 1];
|
||||
/* Step 11.1 */
|
||||
for (int j = 0; j <= n; j++) {
|
||||
BigInteger J = BigInteger.valueOf(j);
|
||||
BigInteger tmp = (seed.add(offset).add(J)).mod(twoSl);
|
||||
byte[] vjBytes = hashObj.digest(toByteArray(tmp));
|
||||
V[j] = new BigInteger(1, vjBytes);
|
||||
}
|
||||
/* Step 11.2 */
|
||||
BigInteger W = V[0];
|
||||
for (int i = 1; i < n; i++) {
|
||||
W = W.add(V[i].multiply(TWO.pow(i * outLen)));
|
||||
}
|
||||
W = W.add((V[n].mod(TWO.pow(b)))
|
||||
.multiply(TWO.pow(n * outLen)));
|
||||
/* Step 11.3 */
|
||||
BigInteger twoLm1 = TWO.pow(valueL - 1);
|
||||
BigInteger X = W.add(twoLm1);
|
||||
/* Step 11.4, 11.5 */
|
||||
BigInteger c = X.mod(resultQ.multiply(TWO));
|
||||
resultP = X.subtract(c.subtract(BigInteger.ONE));
|
||||
/* Step 11.6, 11.7 */
|
||||
if (resultP.compareTo(twoLm1) > -1
|
||||
&& resultP.isProbablePrime(primeCertainty)) {
|
||||
/* Step 11.8 */
|
||||
BigInteger[] result = {resultP, resultQ, seed,
|
||||
BigInteger.valueOf(counter)};
|
||||
return result;
|
||||
}
|
||||
/* Step 11.9 */
|
||||
offset = offset.add(BigInteger.valueOf(n)).add(BigInteger.ONE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Generates the <code>g</code> parameter for DSA.
|
||||
*
|
||||
* @param p the prime, <code>p</code>.
|
||||
* @param q the subprime, <code>q</code>.
|
||||
*
|
||||
* @param the <code>g</code>
|
||||
*/
|
||||
private static BigInteger generateG(BigInteger p, BigInteger q) {
|
||||
BigInteger h = BigInteger.ONE;
|
||||
/* Step 1 */
|
||||
BigInteger pMinusOneOverQ = (p.subtract(BigInteger.ONE)).divide(q);
|
||||
BigInteger resultG = BigInteger.ONE;
|
||||
while (resultG.compareTo(TWO) < 0) {
|
||||
/* Step 3 */
|
||||
resultG = h.modPow(pMinusOneOverQ, p);
|
||||
h = h.add(BigInteger.ONE);
|
||||
}
|
||||
return resultG;
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts the result of a BigInteger.toByteArray call to an exact
|
||||
* signed magnitude representation for any positive number.
|
||||
*/
|
||||
private static byte[] toByteArray(BigInteger bigInt) {
|
||||
byte[] result = bigInt.toByteArray();
|
||||
if (result[0] == 0) {
|
||||
byte[] tmp = new byte[result.length - 1];
|
||||
System.arraycopy(result, 1, tmp, 0, tmp.length);
|
||||
result = tmp;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
142
jdkSrc/jdk8/sun/security/provider/DSAParameters.java
Normal file
142
jdkSrc/jdk8/sun/security/provider/DSAParameters.java
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.io.*;
|
||||
import java.math.BigInteger;
|
||||
import java.security.AlgorithmParametersSpi;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.security.spec.DSAParameterSpec;
|
||||
import java.security.spec.InvalidParameterSpecException;
|
||||
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.util.DerValue;
|
||||
import sun.security.util.DerOutputStream;
|
||||
|
||||
/**
|
||||
* This class implements the parameter set used by the
|
||||
* Digital Signature Algorithm as specified in the FIPS 186
|
||||
* standard.
|
||||
*
|
||||
* @author Jan Luehe
|
||||
*
|
||||
*
|
||||
* @since 1.2
|
||||
*/
|
||||
|
||||
public class DSAParameters extends AlgorithmParametersSpi {
|
||||
|
||||
// the prime (p)
|
||||
protected BigInteger p;
|
||||
|
||||
// the sub-prime (q)
|
||||
protected BigInteger q;
|
||||
|
||||
// the base (g)
|
||||
protected BigInteger g;
|
||||
|
||||
protected void engineInit(AlgorithmParameterSpec paramSpec)
|
||||
throws InvalidParameterSpecException {
|
||||
if (!(paramSpec instanceof DSAParameterSpec)) {
|
||||
throw new InvalidParameterSpecException
|
||||
("Inappropriate parameter specification");
|
||||
}
|
||||
this.p = ((DSAParameterSpec)paramSpec).getP();
|
||||
this.q = ((DSAParameterSpec)paramSpec).getQ();
|
||||
this.g = ((DSAParameterSpec)paramSpec).getG();
|
||||
}
|
||||
|
||||
protected void engineInit(byte[] params) throws IOException {
|
||||
DerValue encodedParams = new DerValue(params);
|
||||
|
||||
if (encodedParams.tag != DerValue.tag_Sequence) {
|
||||
throw new IOException("DSA params parsing error");
|
||||
}
|
||||
|
||||
encodedParams.data.reset();
|
||||
|
||||
this.p = encodedParams.data.getBigInteger();
|
||||
this.q = encodedParams.data.getBigInteger();
|
||||
this.g = encodedParams.data.getBigInteger();
|
||||
|
||||
if (encodedParams.data.available() != 0) {
|
||||
throw new IOException("encoded params have " +
|
||||
encodedParams.data.available() +
|
||||
" extra bytes");
|
||||
}
|
||||
}
|
||||
|
||||
protected void engineInit(byte[] params, String decodingMethod)
|
||||
throws IOException {
|
||||
engineInit(params);
|
||||
}
|
||||
|
||||
protected <T extends AlgorithmParameterSpec>
|
||||
T engineGetParameterSpec(Class<T> paramSpec)
|
||||
throws InvalidParameterSpecException
|
||||
{
|
||||
try {
|
||||
Class<?> dsaParamSpec = Class.forName
|
||||
("java.security.spec.DSAParameterSpec");
|
||||
if (dsaParamSpec.isAssignableFrom(paramSpec)) {
|
||||
return paramSpec.cast(
|
||||
new DSAParameterSpec(this.p, this.q, this.g));
|
||||
} else {
|
||||
throw new InvalidParameterSpecException
|
||||
("Inappropriate parameter Specification");
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new InvalidParameterSpecException
|
||||
("Unsupported parameter specification: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
protected byte[] engineGetEncoded() throws IOException {
|
||||
DerOutputStream out = new DerOutputStream();
|
||||
DerOutputStream bytes = new DerOutputStream();
|
||||
|
||||
bytes.putInteger(p);
|
||||
bytes.putInteger(q);
|
||||
bytes.putInteger(g);
|
||||
out.write(DerValue.tag_Sequence, bytes);
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
protected byte[] engineGetEncoded(String encodingMethod)
|
||||
throws IOException {
|
||||
return engineGetEncoded();
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a formatted string describing the parameters.
|
||||
*/
|
||||
protected String engineToString() {
|
||||
return "\n\tp: " + Debug.toHexString(p)
|
||||
+ "\n\tq: " + Debug.toHexString(q)
|
||||
+ "\n\tg: " + Debug.toHexString(g)
|
||||
+ "\n";
|
||||
}
|
||||
}
|
||||
155
jdkSrc/jdk8/sun/security/provider/DSAPrivateKey.java
Normal file
155
jdkSrc/jdk8/sun/security/provider/DSAPrivateKey.java
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import java.math.BigInteger;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.ProviderException;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.spec.DSAParameterSpec;
|
||||
import java.security.spec.InvalidParameterSpecException;
|
||||
import java.security.interfaces.DSAParams;
|
||||
|
||||
import sun.security.x509.AlgIdDSA;
|
||||
import sun.security.pkcs.PKCS8Key;
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.util.DerValue;
|
||||
import sun.security.util.DerInputStream;
|
||||
import sun.security.util.DerOutputStream;
|
||||
|
||||
/**
|
||||
* A PKCS#8 private key for the Digital Signature Algorithm.
|
||||
*
|
||||
* @author Benjamin Renaud
|
||||
*
|
||||
*
|
||||
* @see DSAPublicKey
|
||||
* @see AlgIdDSA
|
||||
* @see DSA
|
||||
*/
|
||||
|
||||
public final class DSAPrivateKey extends PKCS8Key
|
||||
implements java.security.interfaces.DSAPrivateKey, Serializable {
|
||||
|
||||
/** use serialVersionUID from JDK 1.1. for interoperability */
|
||||
private static final long serialVersionUID = -3244453684193605938L;
|
||||
|
||||
/* the private key */
|
||||
private BigInteger x;
|
||||
|
||||
/*
|
||||
* Keep this constructor for backwards compatibility with JDK1.1.
|
||||
*/
|
||||
public DSAPrivateKey() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a DSA private key out of a private key and three parameters.
|
||||
*/
|
||||
public DSAPrivateKey(BigInteger x, BigInteger p,
|
||||
BigInteger q, BigInteger g)
|
||||
throws InvalidKeyException {
|
||||
this.x = x;
|
||||
algid = new AlgIdDSA(p, q, g);
|
||||
|
||||
try {
|
||||
key = new DerValue(DerValue.tag_Integer,
|
||||
x.toByteArray()).toByteArray();
|
||||
encode();
|
||||
} catch (IOException e) {
|
||||
InvalidKeyException ike = new InvalidKeyException(
|
||||
"could not DER encode x: " + e.getMessage());
|
||||
ike.initCause(e);
|
||||
throw ike;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a DSA private key from its DER encoding (PKCS #8).
|
||||
*/
|
||||
public DSAPrivateKey(byte[] encoded) throws InvalidKeyException {
|
||||
clearOldKey();
|
||||
decode(encoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the DSA parameters associated with this key, or null if the
|
||||
* parameters could not be parsed.
|
||||
*/
|
||||
public DSAParams getParams() {
|
||||
try {
|
||||
if (algid instanceof DSAParams) {
|
||||
return (DSAParams)algid;
|
||||
} else {
|
||||
DSAParameterSpec paramSpec;
|
||||
AlgorithmParameters algParams = algid.getParameters();
|
||||
if (algParams == null) {
|
||||
return null;
|
||||
}
|
||||
paramSpec = algParams.getParameterSpec(DSAParameterSpec.class);
|
||||
return (DSAParams)paramSpec;
|
||||
}
|
||||
} catch (InvalidParameterSpecException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw private key, x, without the parameters.
|
||||
*
|
||||
* @see getParameters
|
||||
*/
|
||||
public BigInteger getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
private void clearOldKey() {
|
||||
int i;
|
||||
if (this.encodedKey != null) {
|
||||
for (i = 0; i < this.encodedKey.length; i++) {
|
||||
this.encodedKey[i] = (byte)0x00;
|
||||
}
|
||||
}
|
||||
if (this.key != null) {
|
||||
for (i = 0; i < this.key.length; i++) {
|
||||
this.key[i] = (byte)0x00;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void parseKeyBits() throws InvalidKeyException {
|
||||
try {
|
||||
DerInputStream in = new DerInputStream(key);
|
||||
x = in.getBigInteger();
|
||||
} catch (IOException e) {
|
||||
InvalidKeyException ike = new InvalidKeyException(e.getMessage());
|
||||
ike.initCause(e);
|
||||
throw ike;
|
||||
}
|
||||
}
|
||||
}
|
||||
154
jdkSrc/jdk8/sun/security/provider/DSAPublicKey.java
Normal file
154
jdkSrc/jdk8/sun/security/provider/DSAPublicKey.java
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import java.math.BigInteger;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.ProviderException;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.spec.DSAParameterSpec;
|
||||
import java.security.spec.InvalidParameterSpecException;
|
||||
import java.security.interfaces.DSAParams;
|
||||
|
||||
import sun.security.x509.X509Key;
|
||||
import sun.security.x509.AlgIdDSA;
|
||||
import sun.security.util.BitArray;
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.util.DerValue;
|
||||
import sun.security.util.DerInputStream;
|
||||
import sun.security.util.DerOutputStream;
|
||||
|
||||
/**
|
||||
* An X.509 public key for the Digital Signature Algorithm.
|
||||
*
|
||||
* @author Benjamin Renaud
|
||||
*
|
||||
*
|
||||
* @see DSAPrivateKey
|
||||
* @see AlgIdDSA
|
||||
* @see DSA
|
||||
*/
|
||||
|
||||
public class DSAPublicKey extends X509Key
|
||||
implements java.security.interfaces.DSAPublicKey, Serializable {
|
||||
|
||||
/** use serialVersionUID from JDK 1.1. for interoperability */
|
||||
private static final long serialVersionUID = -2994193307391104133L;
|
||||
|
||||
/* the public key */
|
||||
private BigInteger y;
|
||||
|
||||
/*
|
||||
* Keep this constructor for backwards compatibility with JDK1.1.
|
||||
*/
|
||||
public DSAPublicKey() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a DSA public key out of a public key and three parameters.
|
||||
* The p, q, and g parameters may be null, but if so, parameters will need
|
||||
* to be supplied from some other source before this key can be used in
|
||||
* cryptographic operations. PKIX RFC2459bis explicitly allows DSA public
|
||||
* keys without parameters, where the parameters are provided in the
|
||||
* issuer's DSA public key.
|
||||
*
|
||||
* @param y the actual key bits
|
||||
* @param p DSA parameter p, may be null if all of p, q, and g are null.
|
||||
* @param q DSA parameter q, may be null if all of p, q, and g are null.
|
||||
* @param g DSA parameter g, may be null if all of p, q, and g are null.
|
||||
*/
|
||||
public DSAPublicKey(BigInteger y, BigInteger p, BigInteger q,
|
||||
BigInteger g)
|
||||
throws InvalidKeyException {
|
||||
this.y = y;
|
||||
algid = new AlgIdDSA(p, q, g);
|
||||
|
||||
try {
|
||||
byte[] keyArray = new DerValue(DerValue.tag_Integer,
|
||||
y.toByteArray()).toByteArray();
|
||||
setKey(new BitArray(keyArray.length*8, keyArray));
|
||||
encode();
|
||||
} catch (IOException e) {
|
||||
throw new InvalidKeyException("could not DER encode y: " +
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a DSA public key from its DER encoding (X.509).
|
||||
*/
|
||||
public DSAPublicKey(byte[] encoded) throws InvalidKeyException {
|
||||
decode(encoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the DSA parameters associated with this key, or null if the
|
||||
* parameters could not be parsed.
|
||||
*/
|
||||
public DSAParams getParams() {
|
||||
try {
|
||||
if (algid instanceof DSAParams) {
|
||||
return (DSAParams)algid;
|
||||
} else {
|
||||
DSAParameterSpec paramSpec;
|
||||
AlgorithmParameters algParams = algid.getParameters();
|
||||
if (algParams == null) {
|
||||
return null;
|
||||
}
|
||||
paramSpec = algParams.getParameterSpec(DSAParameterSpec.class);
|
||||
return (DSAParams)paramSpec;
|
||||
}
|
||||
} catch (InvalidParameterSpecException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw public value, y, without the parameters.
|
||||
*
|
||||
* @see getParameters
|
||||
*/
|
||||
public BigInteger getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Sun DSA Public Key\n Parameters:" + algid
|
||||
+ "\n y:\n" + Debug.toHexString(y) + "\n";
|
||||
}
|
||||
|
||||
protected void parseKeyBits() throws InvalidKeyException {
|
||||
try {
|
||||
DerInputStream in = new DerInputStream(getKey().toByteArray());
|
||||
y = in.getBigInteger();
|
||||
} catch (IOException e) {
|
||||
throw new InvalidKeyException("Invalid key: y value\n" +
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
97
jdkSrc/jdk8/sun/security/provider/DSAPublicKeyImpl.java
Normal file
97
jdkSrc/jdk8/sun/security/provider/DSAPublicKeyImpl.java
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyRep;
|
||||
import java.security.InvalidKeyException;
|
||||
|
||||
/**
|
||||
* An X.509 public key for the Digital Signature Algorithm.
|
||||
* <p>
|
||||
* The difference between DSAPublicKeyImpl and DSAPublicKey is that
|
||||
* DSAPublicKeyImpl calls writeReplace with KeyRep, and DSAPublicKey
|
||||
* calls writeObject.
|
||||
* <p>
|
||||
* See the comments in DSAKeyFactory, 4532506, and 6232513.
|
||||
*
|
||||
*/
|
||||
|
||||
public final class DSAPublicKeyImpl extends DSAPublicKey {
|
||||
|
||||
private static final long serialVersionUID = 7819830118247182730L;
|
||||
|
||||
/**
|
||||
* Make a DSA public key out of a public key and three parameters.
|
||||
* The p, q, and g parameters may be null, but if so, parameters will need
|
||||
* to be supplied from some other source before this key can be used in
|
||||
* cryptographic operations. PKIX RFC2459bis explicitly allows DSA public
|
||||
* keys without parameters, where the parameters are provided in the
|
||||
* issuer's DSA public key.
|
||||
*
|
||||
* @param y the actual key bits
|
||||
* @param p DSA parameter p, may be null if all of p, q, and g are null.
|
||||
* @param q DSA parameter q, may be null if all of p, q, and g are null.
|
||||
* @param g DSA parameter g, may be null if all of p, q, and g are null.
|
||||
*/
|
||||
public DSAPublicKeyImpl(BigInteger y, BigInteger p, BigInteger q,
|
||||
BigInteger g)
|
||||
throws InvalidKeyException {
|
||||
super(y, p, q, g);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a DSA public key from its DER encoding (X.509).
|
||||
*/
|
||||
public DSAPublicKeyImpl(byte[] encoded) throws InvalidKeyException {
|
||||
super(encoded);
|
||||
}
|
||||
|
||||
private Object writeReplace() throws java.io.ObjectStreamException {
|
||||
return new KeyRep(KeyRep.Type.PUBLIC,
|
||||
getAlgorithm(),
|
||||
getFormat(),
|
||||
getEncoded());
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the state of this object from the stream.
|
||||
* <p>
|
||||
* Deserialization of this object is not supported.
|
||||
*
|
||||
* @param stream the {@code ObjectInputStream} from which data is read
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws ClassNotFoundException if a serialized class cannot be loaded
|
||||
*/
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException(
|
||||
"DSAPublicKeyImpl keys are not directly deserializable");
|
||||
}
|
||||
}
|
||||
246
jdkSrc/jdk8/sun/security/provider/DigestBase.java
Normal file
246
jdkSrc/jdk8/sun/security/provider/DigestBase.java
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.security.MessageDigestSpi;
|
||||
import java.security.DigestException;
|
||||
import java.security.ProviderException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Common base message digest implementation for the Sun provider.
|
||||
* It implements all the JCA methods as suitable for a Java message digest
|
||||
* implementation of an algorithm based on a compression function (as all
|
||||
* commonly used algorithms are). The individual digest subclasses only need to
|
||||
* implement the following methods:
|
||||
*
|
||||
* . abstract void implCompress(byte[] b, int ofs);
|
||||
* . abstract void implDigest(byte[] out, int ofs);
|
||||
* . abstract void implReset();
|
||||
*
|
||||
* See the inline documentation for details.
|
||||
*
|
||||
* @since 1.5
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
abstract class DigestBase extends MessageDigestSpi implements Cloneable {
|
||||
|
||||
// one element byte array, temporary storage for update(byte)
|
||||
private byte[] oneByte;
|
||||
|
||||
// algorithm name to use in the exception message
|
||||
private final String algorithm;
|
||||
// length of the message digest in bytes
|
||||
private final int digestLength;
|
||||
|
||||
// size of the input to the compression function in bytes
|
||||
private final int blockSize;
|
||||
// buffer to store partial blocks, blockSize bytes large
|
||||
// Subclasses should not access this array directly except possibly in their
|
||||
// implDigest() method. See MD5.java as an example.
|
||||
byte[] buffer;
|
||||
// offset into buffer
|
||||
private int bufOfs;
|
||||
|
||||
// number of bytes processed so far. subclasses should not modify
|
||||
// this value.
|
||||
// also used as a flag to indicate reset status
|
||||
// -1: need to call engineReset() before next call to update()
|
||||
// 0: is already reset
|
||||
long bytesProcessed;
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
*/
|
||||
DigestBase(String algorithm, int digestLength, int blockSize) {
|
||||
super();
|
||||
this.algorithm = algorithm;
|
||||
this.digestLength = digestLength;
|
||||
this.blockSize = blockSize;
|
||||
buffer = new byte[blockSize];
|
||||
}
|
||||
|
||||
// return digest length. See JCA doc.
|
||||
protected final int engineGetDigestLength() {
|
||||
return digestLength;
|
||||
}
|
||||
|
||||
// single byte update. See JCA doc.
|
||||
protected final void engineUpdate(byte b) {
|
||||
if (oneByte == null) {
|
||||
oneByte = new byte[1];
|
||||
}
|
||||
oneByte[0] = b;
|
||||
engineUpdate(oneByte, 0, 1);
|
||||
}
|
||||
|
||||
// array update. See JCA doc.
|
||||
protected final void engineUpdate(byte[] b, int ofs, int len) {
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
if ((ofs < 0) || (len < 0) || (ofs > b.length - len)) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
if (bytesProcessed < 0) {
|
||||
engineReset();
|
||||
}
|
||||
bytesProcessed += len;
|
||||
// if buffer is not empty, we need to fill it before proceeding
|
||||
if (bufOfs != 0) {
|
||||
int n = Math.min(len, blockSize - bufOfs);
|
||||
System.arraycopy(b, ofs, buffer, bufOfs, n);
|
||||
bufOfs += n;
|
||||
ofs += n;
|
||||
len -= n;
|
||||
if (bufOfs >= blockSize) {
|
||||
// compress completed block now
|
||||
implCompress(buffer, 0);
|
||||
bufOfs = 0;
|
||||
}
|
||||
}
|
||||
// compress complete blocks
|
||||
if (len >= blockSize) {
|
||||
int limit = ofs + len;
|
||||
ofs = implCompressMultiBlock(b, ofs, limit - blockSize);
|
||||
len = limit - ofs;
|
||||
}
|
||||
// copy remainder to buffer
|
||||
if (len > 0) {
|
||||
System.arraycopy(b, ofs, buffer, 0, len);
|
||||
bufOfs = len;
|
||||
}
|
||||
}
|
||||
|
||||
// compress complete blocks
|
||||
private int implCompressMultiBlock(byte[] b, int ofs, int limit) {
|
||||
implCompressMultiBlockCheck(b, ofs, limit);
|
||||
return implCompressMultiBlock0(b, ofs, limit);
|
||||
}
|
||||
|
||||
private int implCompressMultiBlock0(byte[] b, int ofs, int limit) {
|
||||
for (; ofs <= limit; ofs += blockSize) {
|
||||
implCompress(b, ofs);
|
||||
}
|
||||
return ofs;
|
||||
}
|
||||
|
||||
private void implCompressMultiBlockCheck(byte[] b, int ofs, int limit) {
|
||||
if (limit < 0) {
|
||||
return; // not an error because implCompressMultiBlockImpl won't execute if limit < 0
|
||||
// and an exception is thrown if ofs < 0.
|
||||
}
|
||||
|
||||
Objects.requireNonNull(b);
|
||||
|
||||
if (ofs < 0 || ofs >= b.length) {
|
||||
throw new ArrayIndexOutOfBoundsException(ofs);
|
||||
}
|
||||
|
||||
int endIndex = (limit / blockSize) * blockSize + blockSize - 1;
|
||||
if (endIndex >= b.length) {
|
||||
throw new ArrayIndexOutOfBoundsException(endIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// reset this object. See JCA doc.
|
||||
protected final void engineReset() {
|
||||
if (bytesProcessed == 0) {
|
||||
// already reset, ignore
|
||||
return;
|
||||
}
|
||||
implReset();
|
||||
bufOfs = 0;
|
||||
bytesProcessed = 0;
|
||||
Arrays.fill(buffer, (byte) 0x00);
|
||||
}
|
||||
|
||||
// return the digest. See JCA doc.
|
||||
protected final byte[] engineDigest() {
|
||||
byte[] b = new byte[digestLength];
|
||||
try {
|
||||
engineDigest(b, 0, b.length);
|
||||
} catch (DigestException e) {
|
||||
throw (ProviderException)
|
||||
new ProviderException("Internal error").initCause(e);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
// return the digest in the specified array. See JCA doc.
|
||||
protected final int engineDigest(byte[] out, int ofs, int len)
|
||||
throws DigestException {
|
||||
if (len < digestLength) {
|
||||
throw new DigestException("Length must be at least "
|
||||
+ digestLength + " for " + algorithm + "digests");
|
||||
}
|
||||
if ((ofs < 0) || (len < 0) || (ofs > out.length - len)) {
|
||||
throw new DigestException("Buffer too short to store digest");
|
||||
}
|
||||
if (bytesProcessed < 0) {
|
||||
engineReset();
|
||||
}
|
||||
implDigest(out, ofs);
|
||||
bytesProcessed = -1;
|
||||
return digestLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Core compression function. Processes blockSize bytes at a time
|
||||
* and updates the state of this object.
|
||||
*/
|
||||
abstract void implCompress(byte[] b, int ofs);
|
||||
|
||||
/**
|
||||
* Return the digest. Subclasses do not need to reset() themselves,
|
||||
* DigestBase calls implReset() when necessary.
|
||||
*/
|
||||
abstract void implDigest(byte[] out, int ofs);
|
||||
|
||||
/**
|
||||
* Reset subclass specific state to their initial values. DigestBase
|
||||
* calls this method when necessary.
|
||||
*/
|
||||
abstract void implReset();
|
||||
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
DigestBase copy = (DigestBase) super.clone();
|
||||
copy.buffer = copy.buffer.clone();
|
||||
return copy;
|
||||
}
|
||||
|
||||
// padding used for the MD5, and SHA-* message digests
|
||||
static final byte[] padding;
|
||||
|
||||
static {
|
||||
// we need 128 byte padding for SHA-384/512
|
||||
// and an additional 8 bytes for the high 8 bytes of the 16
|
||||
// byte bit counter in SHA-384/512
|
||||
padding = new byte[136];
|
||||
padding[0] = (byte)0x80;
|
||||
}
|
||||
}
|
||||
902
jdkSrc/jdk8/sun/security/provider/DomainKeyStore.java
Normal file
902
jdkSrc/jdk8/sun/security/provider/DomainKeyStore.java
Normal file
@@ -0,0 +1,902 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.security.*;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.*;
|
||||
|
||||
import sun.misc.IOUtils;
|
||||
import sun.security.pkcs.EncryptedPrivateKeyInfo;
|
||||
import sun.security.util.PolicyUtil;
|
||||
|
||||
/**
|
||||
* This class provides the domain keystore type identified as "DKS".
|
||||
* DKS presents a collection of separate keystores as a single logical keystore.
|
||||
* The collection of keystores is specified in a domain configuration file which
|
||||
* is passed to DKS in a {@link DomainLoadStoreParameter}.
|
||||
* <p>
|
||||
* The following properties are supported:
|
||||
* <dl>
|
||||
* <dt> {@code keystoreType="<type>"} </dt>
|
||||
* <dd> The keystore type. </dd>
|
||||
* <dt> {@code keystoreURI="<url>"} </dt>
|
||||
* <dd> The keystore location. </dd>
|
||||
* <dt> {@code keystoreProviderName="<name>"} </dt>
|
||||
* <dd> The name of the keystore's JCE provider. </dd>
|
||||
* <dt> {@code keystorePasswordEnv="<environment-variable>"} </dt>
|
||||
* <dd> The environment variable that stores a keystore password.
|
||||
* <dt> {@code entryNameSeparator="<separator>"} </dt>
|
||||
* <dd> The separator between a keystore name prefix and an entry name.
|
||||
* When specified, it applies to all the entries in a domain.
|
||||
* Its default value is a space. </dd>
|
||||
* </dl>
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
|
||||
abstract class DomainKeyStore extends KeyStoreSpi {
|
||||
|
||||
// regular DKS
|
||||
public static final class DKS extends DomainKeyStore {
|
||||
String convertAlias(String alias) {
|
||||
return alias.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
}
|
||||
|
||||
// DKS property names
|
||||
private static final String ENTRY_NAME_SEPARATOR = "entrynameseparator";
|
||||
private static final String KEYSTORE_PROVIDER_NAME = "keystoreprovidername";
|
||||
private static final String KEYSTORE_TYPE = "keystoretype";
|
||||
private static final String KEYSTORE_URI = "keystoreuri";
|
||||
private static final String KEYSTORE_PASSWORD_ENV = "keystorepasswordenv";
|
||||
|
||||
// RegEx meta characters
|
||||
private static final String REGEX_META = ".$|()[{^?*+\\";
|
||||
|
||||
// Default prefix for keystores loaded-by-stream
|
||||
private static final String DEFAULT_STREAM_PREFIX = "iostream";
|
||||
private int streamCounter = 1;
|
||||
private String entryNameSeparator = " ";
|
||||
private String entryNameSeparatorRegEx = " ";
|
||||
|
||||
// Default keystore type
|
||||
private static final String DEFAULT_KEYSTORE_TYPE =
|
||||
KeyStore.getDefaultType();
|
||||
|
||||
// Domain keystores
|
||||
private final Map<String, KeyStore> keystores = new HashMap<>();
|
||||
|
||||
DomainKeyStore() {
|
||||
}
|
||||
|
||||
// convert an alias to internal form, overridden in subclasses:
|
||||
// lower case for regular DKS
|
||||
abstract String convertAlias(String alias);
|
||||
|
||||
/**
|
||||
* Returns the key associated with the given alias, using the given
|
||||
* password to recover it.
|
||||
*
|
||||
* @param alias the alias name
|
||||
* @param password the password for recovering the key
|
||||
*
|
||||
* @return the requested key, or null if the given alias does not exist
|
||||
* or does not identify a <i>key entry</i>.
|
||||
*
|
||||
* @exception NoSuchAlgorithmException if the algorithm for recovering the
|
||||
* key cannot be found
|
||||
* @exception UnrecoverableKeyException if the key cannot be recovered
|
||||
* (e.g., the given password is wrong).
|
||||
*/
|
||||
public Key engineGetKey(String alias, char[] password)
|
||||
throws NoSuchAlgorithmException, UnrecoverableKeyException
|
||||
{
|
||||
AbstractMap.SimpleEntry<String, Collection<KeyStore>> pair =
|
||||
getKeystoresForReading(alias);
|
||||
Key key = null;
|
||||
|
||||
try {
|
||||
String entryAlias = pair.getKey();
|
||||
for (KeyStore keystore : pair.getValue()) {
|
||||
key = keystore.getKey(entryAlias, password);
|
||||
if (key != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (KeyStoreException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the certificate chain associated with the given alias.
|
||||
*
|
||||
* @param alias the alias name
|
||||
*
|
||||
* @return the certificate chain (ordered with the user's certificate first
|
||||
* and the root certificate authority last), or null if the given alias
|
||||
* does not exist or does not contain a certificate chain (i.e., the given
|
||||
* alias identifies either a <i>trusted certificate entry</i> or a
|
||||
* <i>key entry</i> without a certificate chain).
|
||||
*/
|
||||
public Certificate[] engineGetCertificateChain(String alias) {
|
||||
|
||||
AbstractMap.SimpleEntry<String, Collection<KeyStore>> pair =
|
||||
getKeystoresForReading(alias);
|
||||
Certificate[] chain = null;
|
||||
|
||||
try {
|
||||
String entryAlias = pair.getKey();
|
||||
for (KeyStore keystore : pair.getValue()) {
|
||||
chain = keystore.getCertificateChain(entryAlias);
|
||||
if (chain != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (KeyStoreException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
return chain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the certificate associated with the given alias.
|
||||
*
|
||||
* <p>If the given alias name identifies a
|
||||
* <i>trusted certificate entry</i>, the certificate associated with that
|
||||
* entry is returned. If the given alias name identifies a
|
||||
* <i>key entry</i>, the first element of the certificate chain of that
|
||||
* entry is returned, or null if that entry does not have a certificate
|
||||
* chain.
|
||||
*
|
||||
* @param alias the alias name
|
||||
*
|
||||
* @return the certificate, or null if the given alias does not exist or
|
||||
* does not contain a certificate.
|
||||
*/
|
||||
public Certificate engineGetCertificate(String alias) {
|
||||
|
||||
AbstractMap.SimpleEntry<String, Collection<KeyStore>> pair =
|
||||
getKeystoresForReading(alias);
|
||||
Certificate cert = null;
|
||||
|
||||
try {
|
||||
String entryAlias = pair.getKey();
|
||||
for (KeyStore keystore : pair.getValue()) {
|
||||
cert = keystore.getCertificate(entryAlias);
|
||||
if (cert != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (KeyStoreException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
return cert;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the creation date of the entry identified by the given alias.
|
||||
*
|
||||
* @param alias the alias name
|
||||
*
|
||||
* @return the creation date of this entry, or null if the given alias does
|
||||
* not exist
|
||||
*/
|
||||
public Date engineGetCreationDate(String alias) {
|
||||
|
||||
AbstractMap.SimpleEntry<String, Collection<KeyStore>> pair =
|
||||
getKeystoresForReading(alias);
|
||||
Date date = null;
|
||||
|
||||
try {
|
||||
String entryAlias = pair.getKey();
|
||||
for (KeyStore keystore : pair.getValue()) {
|
||||
date = keystore.getCreationDate(entryAlias);
|
||||
if (date != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (KeyStoreException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the given private key to the given alias, protecting
|
||||
* it with the given password as defined in PKCS8.
|
||||
*
|
||||
* <p>The given java.security.PrivateKey <code>key</code> must
|
||||
* be accompanied by a certificate chain certifying the
|
||||
* corresponding public key.
|
||||
*
|
||||
* <p>If the given alias already exists, the keystore information
|
||||
* associated with it is overridden by the given key and certificate
|
||||
* chain.
|
||||
*
|
||||
* @param alias the alias name
|
||||
* @param key the private key to be associated with the alias
|
||||
* @param password the password to protect the key
|
||||
* @param chain the certificate chain for the corresponding public
|
||||
* key (only required if the given key is of type
|
||||
* <code>java.security.PrivateKey</code>).
|
||||
*
|
||||
* @exception KeyStoreException if the given key is not a private key,
|
||||
* cannot be protected, or this operation fails for some other reason
|
||||
*/
|
||||
public void engineSetKeyEntry(String alias, Key key, char[] password,
|
||||
Certificate[] chain)
|
||||
throws KeyStoreException
|
||||
{
|
||||
AbstractMap.SimpleEntry<String,
|
||||
AbstractMap.SimpleEntry<String, KeyStore>> pair =
|
||||
getKeystoreForWriting(alias);
|
||||
|
||||
if (pair == null) {
|
||||
throw new KeyStoreException("Error setting key entry for '" +
|
||||
alias + "'");
|
||||
}
|
||||
String entryAlias = pair.getKey();
|
||||
Map.Entry<String, KeyStore> keystore = pair.getValue();
|
||||
keystore.getValue().setKeyEntry(entryAlias, key, password, chain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the given key (that has already been protected) to the given
|
||||
* alias.
|
||||
*
|
||||
* <p>If the protected key is of type
|
||||
* <code>java.security.PrivateKey</code>, it must be accompanied by a
|
||||
* certificate chain certifying the corresponding public key. If the
|
||||
* underlying keystore implementation is of type <code>jks</code>,
|
||||
* <code>key</code> must be encoded as an
|
||||
* <code>EncryptedPrivateKeyInfo</code> as defined in the PKCS #8 standard.
|
||||
*
|
||||
* <p>If the given alias already exists, the keystore information
|
||||
* associated with it is overridden by the given key (and possibly
|
||||
* certificate chain).
|
||||
*
|
||||
* @param alias the alias name
|
||||
* @param key the key (in protected format) to be associated with the alias
|
||||
* @param chain the certificate chain for the corresponding public
|
||||
* key (only useful if the protected key is of type
|
||||
* <code>java.security.PrivateKey</code>).
|
||||
*
|
||||
* @exception KeyStoreException if this operation fails.
|
||||
*/
|
||||
public void engineSetKeyEntry(String alias, byte[] key,
|
||||
Certificate[] chain)
|
||||
throws KeyStoreException
|
||||
{
|
||||
AbstractMap.SimpleEntry<String,
|
||||
AbstractMap.SimpleEntry<String, KeyStore>> pair =
|
||||
getKeystoreForWriting(alias);
|
||||
|
||||
if (pair == null) {
|
||||
throw new KeyStoreException(
|
||||
"Error setting protected key entry for '" + alias + "'");
|
||||
}
|
||||
String entryAlias = pair.getKey();
|
||||
Map.Entry<String, KeyStore> keystore = pair.getValue();
|
||||
keystore.getValue().setKeyEntry(entryAlias, key, chain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the given certificate to the given alias.
|
||||
*
|
||||
* <p>If the given alias already exists in this keystore and identifies a
|
||||
* <i>trusted certificate entry</i>, the certificate associated with it is
|
||||
* overridden by the given certificate.
|
||||
*
|
||||
* @param alias the alias name
|
||||
* @param cert the certificate
|
||||
*
|
||||
* @exception KeyStoreException if the given alias already exists and does
|
||||
* not identify a <i>trusted certificate entry</i>, or this operation
|
||||
* fails for some other reason.
|
||||
*/
|
||||
public void engineSetCertificateEntry(String alias, Certificate cert)
|
||||
throws KeyStoreException
|
||||
{
|
||||
AbstractMap.SimpleEntry<String,
|
||||
AbstractMap.SimpleEntry<String, KeyStore>> pair =
|
||||
getKeystoreForWriting(alias);
|
||||
|
||||
if (pair == null) {
|
||||
throw new KeyStoreException("Error setting certificate entry for '"
|
||||
+ alias + "'");
|
||||
}
|
||||
String entryAlias = pair.getKey();
|
||||
Map.Entry<String, KeyStore> keystore = pair.getValue();
|
||||
keystore.getValue().setCertificateEntry(entryAlias, cert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the entry identified by the given alias from this keystore.
|
||||
*
|
||||
* @param alias the alias name
|
||||
*
|
||||
* @exception KeyStoreException if the entry cannot be removed.
|
||||
*/
|
||||
public void engineDeleteEntry(String alias) throws KeyStoreException
|
||||
{
|
||||
AbstractMap.SimpleEntry<String,
|
||||
AbstractMap.SimpleEntry<String, KeyStore>> pair =
|
||||
getKeystoreForWriting(alias);
|
||||
|
||||
if (pair == null) {
|
||||
throw new KeyStoreException("Error deleting entry for '" + alias +
|
||||
"'");
|
||||
}
|
||||
String entryAlias = pair.getKey();
|
||||
Map.Entry<String, KeyStore> keystore = pair.getValue();
|
||||
keystore.getValue().deleteEntry(entryAlias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all the alias names of this keystore.
|
||||
*
|
||||
* @return enumeration of the alias names
|
||||
*/
|
||||
public Enumeration<String> engineAliases() {
|
||||
final Iterator<Map.Entry<String, KeyStore>> iterator =
|
||||
keystores.entrySet().iterator();
|
||||
|
||||
return new Enumeration<String>() {
|
||||
private int index = 0;
|
||||
private Map.Entry<String, KeyStore> keystoresEntry = null;
|
||||
private String prefix = null;
|
||||
private Enumeration<String> aliases = null;
|
||||
|
||||
public boolean hasMoreElements() {
|
||||
try {
|
||||
if (aliases == null) {
|
||||
if (iterator.hasNext()) {
|
||||
keystoresEntry = iterator.next();
|
||||
prefix = keystoresEntry.getKey() +
|
||||
entryNameSeparator;
|
||||
aliases = keystoresEntry.getValue().aliases();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (aliases.hasMoreElements()) {
|
||||
return true;
|
||||
} else {
|
||||
if (iterator.hasNext()) {
|
||||
keystoresEntry = iterator.next();
|
||||
prefix = keystoresEntry.getKey() +
|
||||
entryNameSeparator;
|
||||
aliases = keystoresEntry.getValue().aliases();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (KeyStoreException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return aliases.hasMoreElements();
|
||||
}
|
||||
|
||||
public String nextElement() {
|
||||
if (hasMoreElements()) {
|
||||
return prefix + aliases.nextElement();
|
||||
}
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given alias exists in this keystore.
|
||||
*
|
||||
* @param alias the alias name
|
||||
*
|
||||
* @return true if the alias exists, false otherwise
|
||||
*/
|
||||
public boolean engineContainsAlias(String alias) {
|
||||
|
||||
AbstractMap.SimpleEntry<String, Collection<KeyStore>> pair =
|
||||
getKeystoresForReading(alias);
|
||||
|
||||
try {
|
||||
String entryAlias = pair.getKey();
|
||||
for (KeyStore keystore : pair.getValue()) {
|
||||
if (keystore.containsAlias(entryAlias)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (KeyStoreException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the number of entries in this keystore.
|
||||
*
|
||||
* @return the number of entries in this keystore
|
||||
*/
|
||||
public int engineSize() {
|
||||
|
||||
int size = 0;
|
||||
try {
|
||||
for (KeyStore keystore : keystores.values()) {
|
||||
size += keystore.size();
|
||||
}
|
||||
} catch (KeyStoreException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the entry identified by the given alias is a
|
||||
* <i>key entry</i>, and false otherwise.
|
||||
*
|
||||
* @return true if the entry identified by the given alias is a
|
||||
* <i>key entry</i>, false otherwise.
|
||||
*/
|
||||
public boolean engineIsKeyEntry(String alias) {
|
||||
|
||||
AbstractMap.SimpleEntry<String, Collection<KeyStore>> pair =
|
||||
getKeystoresForReading(alias);
|
||||
|
||||
try {
|
||||
String entryAlias = pair.getKey();
|
||||
for (KeyStore keystore : pair.getValue()) {
|
||||
if (keystore.isKeyEntry(entryAlias)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (KeyStoreException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the entry identified by the given alias is a
|
||||
* <i>trusted certificate entry</i>, and false otherwise.
|
||||
*
|
||||
* @return true if the entry identified by the given alias is a
|
||||
* <i>trusted certificate entry</i>, false otherwise.
|
||||
*/
|
||||
public boolean engineIsCertificateEntry(String alias) {
|
||||
|
||||
AbstractMap.SimpleEntry<String, Collection<KeyStore>> pair =
|
||||
getKeystoresForReading(alias);
|
||||
|
||||
try {
|
||||
String entryAlias = pair.getKey();
|
||||
for (KeyStore keystore : pair.getValue()) {
|
||||
if (keystore.isCertificateEntry(entryAlias)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (KeyStoreException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a keystore entry alias and a list of target keystores.
|
||||
* When the supplied alias prefix identifies a keystore then that single
|
||||
* keystore is returned. When no alias prefix is supplied then all the
|
||||
* keystores are returned.
|
||||
*/
|
||||
private AbstractMap.SimpleEntry<String, Collection<KeyStore>>
|
||||
getKeystoresForReading(String alias) {
|
||||
|
||||
String[] splits = alias.split(this.entryNameSeparatorRegEx, 2);
|
||||
if (splits.length == 2) { // prefixed alias
|
||||
KeyStore keystore = keystores.get(splits[0]);
|
||||
if (keystore != null) {
|
||||
return new AbstractMap.SimpleEntry<>(splits[1],
|
||||
(Collection<KeyStore>) Collections.singleton(keystore));
|
||||
}
|
||||
} else if (splits.length == 1) { // unprefixed alias
|
||||
// Check all keystores for the first occurrence of the alias
|
||||
return new AbstractMap.SimpleEntry<>(alias, keystores.values());
|
||||
}
|
||||
return new AbstractMap.SimpleEntry<>("",
|
||||
(Collection<KeyStore>) Collections.<KeyStore>emptyList());
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a keystore entry alias and a single target keystore.
|
||||
* An alias prefix must be supplied.
|
||||
*/
|
||||
private
|
||||
AbstractMap.SimpleEntry<String, AbstractMap.SimpleEntry<String, KeyStore>>
|
||||
getKeystoreForWriting(String alias) {
|
||||
|
||||
String[] splits = alias.split(this.entryNameSeparator, 2);
|
||||
if (splits.length == 2) { // prefixed alias
|
||||
KeyStore keystore = keystores.get(splits[0]);
|
||||
if (keystore != null) {
|
||||
return new AbstractMap.SimpleEntry<>(splits[1],
|
||||
new AbstractMap.SimpleEntry<>(splits[0], keystore));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the (alias) name of the first keystore entry whose certificate
|
||||
* matches the given certificate.
|
||||
*
|
||||
* <p>This method attempts to match the given certificate with each
|
||||
* keystore entry. If the entry being considered
|
||||
* is a <i>trusted certificate entry</i>, the given certificate is
|
||||
* compared to that entry's certificate. If the entry being considered is
|
||||
* a <i>key entry</i>, the given certificate is compared to the first
|
||||
* element of that entry's certificate chain (if a chain exists).
|
||||
*
|
||||
* @param cert the certificate to match with.
|
||||
*
|
||||
* @return the (alias) name of the first entry with matching certificate,
|
||||
* or null if no such entry exists in this keystore.
|
||||
*/
|
||||
public String engineGetCertificateAlias(Certificate cert) {
|
||||
|
||||
try {
|
||||
|
||||
String alias = null;
|
||||
for (KeyStore keystore : keystores.values()) {
|
||||
if ((alias = keystore.getCertificateAlias(cert)) != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return alias;
|
||||
|
||||
} catch (KeyStoreException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores this keystore to the given output stream, and protects its
|
||||
* integrity with the given password.
|
||||
*
|
||||
* @param stream the output stream to which this keystore is written.
|
||||
* @param password the password to generate the keystore integrity check
|
||||
*
|
||||
* @exception IOException if there was an I/O problem with data
|
||||
* @exception NoSuchAlgorithmException if the appropriate data integrity
|
||||
* algorithm could not be found
|
||||
* @exception CertificateException if any of the certificates included in
|
||||
* the keystore data could not be stored
|
||||
*/
|
||||
public void engineStore(OutputStream stream, char[] password)
|
||||
throws IOException, NoSuchAlgorithmException, CertificateException
|
||||
{
|
||||
// Support storing to a stream only when a single keystore has been
|
||||
// configured
|
||||
try {
|
||||
if (keystores.size() == 1) {
|
||||
keystores.values().iterator().next().store(stream, password);
|
||||
return;
|
||||
}
|
||||
} catch (KeyStoreException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException(
|
||||
"This keystore must be stored using a DomainLoadStoreParameter");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void engineStore(KeyStore.LoadStoreParameter param)
|
||||
throws IOException, NoSuchAlgorithmException, CertificateException
|
||||
{
|
||||
if (param instanceof DomainLoadStoreParameter) {
|
||||
DomainLoadStoreParameter domainParameter =
|
||||
(DomainLoadStoreParameter) param;
|
||||
List<KeyStoreBuilderComponents> builders = getBuilders(
|
||||
domainParameter.getConfiguration(),
|
||||
domainParameter.getProtectionParams());
|
||||
|
||||
for (KeyStoreBuilderComponents builder : builders) {
|
||||
|
||||
try {
|
||||
|
||||
KeyStore.ProtectionParameter pp = builder.protection;
|
||||
if (!(pp instanceof KeyStore.PasswordProtection)) {
|
||||
throw new KeyStoreException(
|
||||
new IllegalArgumentException("ProtectionParameter" +
|
||||
" must be a KeyStore.PasswordProtection"));
|
||||
}
|
||||
char[] password =
|
||||
((KeyStore.PasswordProtection) builder.protection)
|
||||
.getPassword();
|
||||
|
||||
// Store the keystores
|
||||
KeyStore keystore = keystores.get(builder.name);
|
||||
|
||||
try (FileOutputStream stream =
|
||||
new FileOutputStream(builder.file)) {
|
||||
|
||||
keystore.store(stream, password);
|
||||
}
|
||||
} catch (KeyStoreException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedOperationException(
|
||||
"This keystore must be stored using a " +
|
||||
"DomainLoadStoreParameter");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the keystore from the given input stream.
|
||||
*
|
||||
* <p>If a password is given, it is used to check the integrity of the
|
||||
* keystore data. Otherwise, the integrity of the keystore is not checked.
|
||||
*
|
||||
* @param stream the input stream from which the keystore is loaded
|
||||
* @param password the (optional) password used to check the integrity of
|
||||
* the keystore.
|
||||
*
|
||||
* @exception IOException if there is an I/O or format problem with the
|
||||
* keystore data
|
||||
* @exception NoSuchAlgorithmException if the algorithm used to check
|
||||
* the integrity of the keystore cannot be found
|
||||
* @exception CertificateException if any of the certificates in the
|
||||
* keystore could not be loaded
|
||||
*/
|
||||
public void engineLoad(InputStream stream, char[] password)
|
||||
throws IOException, NoSuchAlgorithmException, CertificateException
|
||||
{
|
||||
// Support loading from a stream only for a JKS or default type keystore
|
||||
try {
|
||||
KeyStore keystore = null;
|
||||
|
||||
try {
|
||||
keystore = KeyStore.getInstance("JKS");
|
||||
keystore.load(stream, password);
|
||||
|
||||
} catch (Exception e) {
|
||||
// Retry
|
||||
if (!"JKS".equalsIgnoreCase(DEFAULT_KEYSTORE_TYPE)) {
|
||||
keystore = KeyStore.getInstance(DEFAULT_KEYSTORE_TYPE);
|
||||
keystore.load(stream, password);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
String keystoreName = DEFAULT_STREAM_PREFIX + streamCounter++;
|
||||
keystores.put(keystoreName, keystore);
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new UnsupportedOperationException(
|
||||
"This keystore must be loaded using a " +
|
||||
"DomainLoadStoreParameter");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void engineLoad(KeyStore.LoadStoreParameter param)
|
||||
throws IOException, NoSuchAlgorithmException, CertificateException
|
||||
{
|
||||
if (param instanceof DomainLoadStoreParameter) {
|
||||
DomainLoadStoreParameter domainParameter =
|
||||
(DomainLoadStoreParameter) param;
|
||||
List<KeyStoreBuilderComponents> builders = getBuilders(
|
||||
domainParameter.getConfiguration(),
|
||||
domainParameter.getProtectionParams());
|
||||
|
||||
for (KeyStoreBuilderComponents builder : builders) {
|
||||
|
||||
try {
|
||||
// Load the keystores (file-based and non-file-based)
|
||||
if (builder.file != null) {
|
||||
keystores.put(builder.name,
|
||||
KeyStore.Builder.newInstance(builder.type,
|
||||
builder.provider, builder.file,
|
||||
builder.protection)
|
||||
.getKeyStore());
|
||||
} else {
|
||||
keystores.put(builder.name,
|
||||
KeyStore.Builder.newInstance(builder.type,
|
||||
builder.provider, builder.protection)
|
||||
.getKeyStore());
|
||||
}
|
||||
} catch (KeyStoreException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedOperationException(
|
||||
"This keystore must be loaded using a " +
|
||||
"DomainLoadStoreParameter");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a keystore domain configuration file and associated collection
|
||||
* of keystore passwords to create a collection of KeyStore.Builder.
|
||||
*/
|
||||
private List<KeyStoreBuilderComponents> getBuilders(URI configuration,
|
||||
Map<String, KeyStore.ProtectionParameter> passwords)
|
||||
throws IOException {
|
||||
|
||||
PolicyParser parser = new PolicyParser(true); // expand properties
|
||||
Collection<PolicyParser.DomainEntry> domains = null;
|
||||
List<KeyStoreBuilderComponents> builders = new ArrayList<>();
|
||||
String uriDomain = configuration.getFragment();
|
||||
|
||||
try (InputStreamReader configurationReader =
|
||||
new InputStreamReader(
|
||||
PolicyUtil.getInputStream(configuration.toURL()), "UTF-8")) {
|
||||
parser.read(configurationReader);
|
||||
domains = parser.getDomainEntries();
|
||||
|
||||
} catch (MalformedURLException mue) {
|
||||
throw new IOException(mue);
|
||||
|
||||
} catch (PolicyParser.ParsingException pe) {
|
||||
throw new IOException(pe);
|
||||
}
|
||||
|
||||
for (PolicyParser.DomainEntry domain : domains) {
|
||||
Map<String, String> domainProperties = domain.getProperties();
|
||||
|
||||
if (uriDomain != null &&
|
||||
(!uriDomain.equalsIgnoreCase(domain.getName()))) {
|
||||
continue; // skip this domain
|
||||
}
|
||||
|
||||
if (domainProperties.containsKey(ENTRY_NAME_SEPARATOR)) {
|
||||
this.entryNameSeparator =
|
||||
domainProperties.get(ENTRY_NAME_SEPARATOR);
|
||||
// escape any regex meta characters
|
||||
char ch = 0;
|
||||
StringBuilder s = new StringBuilder();
|
||||
for (int i = 0; i < this.entryNameSeparator.length(); i++) {
|
||||
ch = this.entryNameSeparator.charAt(i);
|
||||
if (REGEX_META.indexOf(ch) != -1) {
|
||||
s.append('\\');
|
||||
}
|
||||
s.append(ch);
|
||||
}
|
||||
this.entryNameSeparatorRegEx = s.toString();
|
||||
}
|
||||
|
||||
Collection<PolicyParser.KeyStoreEntry> keystores =
|
||||
domain.getEntries();
|
||||
for (PolicyParser.KeyStoreEntry keystore : keystores) {
|
||||
String keystoreName = keystore.getName();
|
||||
Map<String, String> properties =
|
||||
new HashMap<>(domainProperties);
|
||||
properties.putAll(keystore.getProperties());
|
||||
|
||||
String keystoreType = DEFAULT_KEYSTORE_TYPE;
|
||||
if (properties.containsKey(KEYSTORE_TYPE)) {
|
||||
keystoreType = properties.get(KEYSTORE_TYPE);
|
||||
}
|
||||
|
||||
Provider keystoreProvider = null;
|
||||
if (properties.containsKey(KEYSTORE_PROVIDER_NAME)) {
|
||||
String keystoreProviderName =
|
||||
properties.get(KEYSTORE_PROVIDER_NAME);
|
||||
keystoreProvider =
|
||||
Security.getProvider(keystoreProviderName);
|
||||
if (keystoreProvider == null) {
|
||||
throw new IOException("Error locating JCE provider: " +
|
||||
keystoreProviderName);
|
||||
}
|
||||
}
|
||||
|
||||
File keystoreFile = null;
|
||||
if (properties.containsKey(KEYSTORE_URI)) {
|
||||
String uri = properties.get(KEYSTORE_URI);
|
||||
|
||||
try {
|
||||
if (uri.startsWith("file://")) {
|
||||
keystoreFile = new File(new URI(uri));
|
||||
} else {
|
||||
keystoreFile = new File(uri);
|
||||
}
|
||||
|
||||
} catch (URISyntaxException | IllegalArgumentException e) {
|
||||
throw new IOException(
|
||||
"Error processing keystore property: " +
|
||||
"keystoreURI=\"" + uri + "\"", e);
|
||||
}
|
||||
}
|
||||
|
||||
KeyStore.ProtectionParameter keystoreProtection = null;
|
||||
if (passwords.containsKey(keystoreName)) {
|
||||
keystoreProtection = passwords.get(keystoreName);
|
||||
|
||||
} else if (properties.containsKey(KEYSTORE_PASSWORD_ENV)) {
|
||||
String env = properties.get(KEYSTORE_PASSWORD_ENV);
|
||||
String pwd = System.getenv(env);
|
||||
if (pwd != null) {
|
||||
keystoreProtection =
|
||||
new KeyStore.PasswordProtection(pwd.toCharArray());
|
||||
} else {
|
||||
throw new IOException(
|
||||
"Error processing keystore property: " +
|
||||
"keystorePasswordEnv=\"" + env + "\"");
|
||||
}
|
||||
} else {
|
||||
keystoreProtection = new KeyStore.PasswordProtection(null);
|
||||
}
|
||||
|
||||
builders.add(new KeyStoreBuilderComponents(keystoreName,
|
||||
keystoreType, keystoreProvider, keystoreFile,
|
||||
keystoreProtection));
|
||||
}
|
||||
break; // skip other domains
|
||||
}
|
||||
if (builders.isEmpty()) {
|
||||
throw new IOException("Error locating domain configuration data " +
|
||||
"for: " + configuration);
|
||||
}
|
||||
|
||||
return builders;
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility class that holds the components used to construct a KeyStore.Builder
|
||||
*/
|
||||
class KeyStoreBuilderComponents {
|
||||
String name;
|
||||
String type;
|
||||
Provider provider;
|
||||
File file;
|
||||
KeyStore.ProtectionParameter protection;
|
||||
|
||||
KeyStoreBuilderComponents(String name, String type, Provider provider,
|
||||
File file, KeyStore.ProtectionParameter protection) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.provider = provider;
|
||||
this.file = file;
|
||||
this.protection = protection;
|
||||
}
|
||||
}
|
||||
}
|
||||
829
jdkSrc/jdk8/sun/security/provider/JavaKeyStore.java
Normal file
829
jdkSrc/jdk8/sun/security/provider/JavaKeyStore.java
Normal file
@@ -0,0 +1,829 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.io.*;
|
||||
import java.security.*;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.*;
|
||||
|
||||
import sun.misc.IOUtils;
|
||||
import sun.security.pkcs.EncryptedPrivateKeyInfo;
|
||||
import sun.security.pkcs12.PKCS12KeyStore;
|
||||
import sun.security.util.Debug;
|
||||
|
||||
/**
|
||||
* This class provides the keystore implementation referred to as "JKS".
|
||||
*
|
||||
* @author Jan Luehe
|
||||
* @author David Brownell
|
||||
*
|
||||
*
|
||||
* @see KeyProtector
|
||||
* @see java.security.KeyStoreSpi
|
||||
* @see KeyTool
|
||||
*
|
||||
* @since 1.2
|
||||
*/
|
||||
|
||||
abstract class JavaKeyStore extends KeyStoreSpi {
|
||||
|
||||
// regular JKS
|
||||
public static final class JKS extends JavaKeyStore {
|
||||
String convertAlias(String alias) {
|
||||
return alias.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
}
|
||||
|
||||
// special JKS that uses case sensitive aliases
|
||||
public static final class CaseExactJKS extends JavaKeyStore {
|
||||
String convertAlias(String alias) {
|
||||
return alias;
|
||||
}
|
||||
}
|
||||
|
||||
// special JKS that supports JKS and PKCS12 file formats
|
||||
public static final class DualFormatJKS extends KeyStoreDelegator {
|
||||
public DualFormatJKS() {
|
||||
super("JKS", JKS.class, "PKCS12", PKCS12KeyStore.class);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Debug debug = Debug.getInstance("keystore");
|
||||
private static final int MAGIC = 0xfeedfeed;
|
||||
private static final int VERSION_1 = 0x01;
|
||||
private static final int VERSION_2 = 0x02;
|
||||
|
||||
// Private keys and their supporting certificate chains
|
||||
private static class KeyEntry {
|
||||
Date date; // the creation date of this entry
|
||||
byte[] protectedPrivKey;
|
||||
Certificate chain[];
|
||||
};
|
||||
|
||||
// Trusted certificates
|
||||
private static class TrustedCertEntry {
|
||||
Date date; // the creation date of this entry
|
||||
Certificate cert;
|
||||
};
|
||||
|
||||
/**
|
||||
* Private keys and certificates are stored in a hashtable.
|
||||
* Hash entries are keyed by alias names.
|
||||
*/
|
||||
private final Hashtable<String, Object> entries;
|
||||
|
||||
JavaKeyStore() {
|
||||
entries = new Hashtable<String, Object>();
|
||||
}
|
||||
|
||||
// convert an alias to internal form, overridden in subclasses:
|
||||
// lower case for regular JKS
|
||||
// original string for CaseExactJKS
|
||||
abstract String convertAlias(String alias);
|
||||
|
||||
/**
|
||||
* Returns the key associated with the given alias, using the given
|
||||
* password to recover it.
|
||||
*
|
||||
* @param alias the alias name
|
||||
* @param password the password for recovering the key
|
||||
*
|
||||
* @return the requested key, or null if the given alias does not exist
|
||||
* or does not identify a <i>key entry</i>.
|
||||
*
|
||||
* @exception NoSuchAlgorithmException if the algorithm for recovering the
|
||||
* key cannot be found
|
||||
* @exception UnrecoverableKeyException if the key cannot be recovered
|
||||
* (e.g., the given password is wrong).
|
||||
*/
|
||||
public Key engineGetKey(String alias, char[] password)
|
||||
throws NoSuchAlgorithmException, UnrecoverableKeyException
|
||||
{
|
||||
Object entry = entries.get(convertAlias(alias));
|
||||
|
||||
if (entry == null || !(entry instanceof KeyEntry)) {
|
||||
return null;
|
||||
}
|
||||
if (password == null) {
|
||||
throw new UnrecoverableKeyException("Password must not be null");
|
||||
}
|
||||
|
||||
byte[] passwordBytes = convertToBytes(password);
|
||||
KeyProtector keyProtector = new KeyProtector(passwordBytes);
|
||||
byte[] encrBytes = ((KeyEntry)entry).protectedPrivKey;
|
||||
EncryptedPrivateKeyInfo encrInfo;
|
||||
try {
|
||||
encrInfo = new EncryptedPrivateKeyInfo(encrBytes);
|
||||
return keyProtector.recover(encrInfo);
|
||||
} catch (IOException ioe) {
|
||||
throw new UnrecoverableKeyException("Private key not stored as "
|
||||
+ "PKCS #8 "
|
||||
+ "EncryptedPrivateKeyInfo");
|
||||
} finally {
|
||||
Arrays.fill(passwordBytes, (byte) 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the certificate chain associated with the given alias.
|
||||
*
|
||||
* @param alias the alias name
|
||||
*
|
||||
* @return the certificate chain (ordered with the user's certificate first
|
||||
* and the root certificate authority last), or null if the given alias
|
||||
* does not exist or does not contain a certificate chain (i.e., the given
|
||||
* alias identifies either a <i>trusted certificate entry</i> or a
|
||||
* <i>key entry</i> without a certificate chain).
|
||||
*/
|
||||
public Certificate[] engineGetCertificateChain(String alias) {
|
||||
Object entry = entries.get(convertAlias(alias));
|
||||
|
||||
if (entry != null && entry instanceof KeyEntry) {
|
||||
if (((KeyEntry)entry).chain == null) {
|
||||
return null;
|
||||
} else {
|
||||
return ((KeyEntry)entry).chain.clone();
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the certificate associated with the given alias.
|
||||
*
|
||||
* <p>If the given alias name identifies a
|
||||
* <i>trusted certificate entry</i>, the certificate associated with that
|
||||
* entry is returned. If the given alias name identifies a
|
||||
* <i>key entry</i>, the first element of the certificate chain of that
|
||||
* entry is returned, or null if that entry does not have a certificate
|
||||
* chain.
|
||||
*
|
||||
* @param alias the alias name
|
||||
*
|
||||
* @return the certificate, or null if the given alias does not exist or
|
||||
* does not contain a certificate.
|
||||
*/
|
||||
public Certificate engineGetCertificate(String alias) {
|
||||
Object entry = entries.get(convertAlias(alias));
|
||||
|
||||
if (entry != null) {
|
||||
if (entry instanceof TrustedCertEntry) {
|
||||
return ((TrustedCertEntry)entry).cert;
|
||||
} else {
|
||||
if (((KeyEntry)entry).chain == null) {
|
||||
return null;
|
||||
} else {
|
||||
return ((KeyEntry)entry).chain[0];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the creation date of the entry identified by the given alias.
|
||||
*
|
||||
* @param alias the alias name
|
||||
*
|
||||
* @return the creation date of this entry, or null if the given alias does
|
||||
* not exist
|
||||
*/
|
||||
public Date engineGetCreationDate(String alias) {
|
||||
Object entry = entries.get(convertAlias(alias));
|
||||
|
||||
if (entry != null) {
|
||||
if (entry instanceof TrustedCertEntry) {
|
||||
return new Date(((TrustedCertEntry)entry).date.getTime());
|
||||
} else {
|
||||
return new Date(((KeyEntry)entry).date.getTime());
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the given private key to the given alias, protecting
|
||||
* it with the given password as defined in PKCS8.
|
||||
*
|
||||
* <p>The given java.security.PrivateKey <code>key</code> must
|
||||
* be accompanied by a certificate chain certifying the
|
||||
* corresponding public key.
|
||||
*
|
||||
* <p>If the given alias already exists, the keystore information
|
||||
* associated with it is overridden by the given key and certificate
|
||||
* chain.
|
||||
*
|
||||
* @param alias the alias name
|
||||
* @param key the private key to be associated with the alias
|
||||
* @param password the password to protect the key
|
||||
* @param chain the certificate chain for the corresponding public
|
||||
* key (only required if the given key is of type
|
||||
* <code>java.security.PrivateKey</code>).
|
||||
*
|
||||
* @exception KeyStoreException if the given key is not a private key,
|
||||
* cannot be protected, or this operation fails for some other reason
|
||||
*/
|
||||
public void engineSetKeyEntry(String alias, Key key, char[] password,
|
||||
Certificate[] chain)
|
||||
throws KeyStoreException
|
||||
{
|
||||
KeyProtector keyProtector;
|
||||
byte[] passwordBytes = null;
|
||||
|
||||
if (!(key instanceof java.security.PrivateKey)) {
|
||||
throw new KeyStoreException("Cannot store non-PrivateKeys");
|
||||
}
|
||||
try {
|
||||
synchronized(entries) {
|
||||
KeyEntry entry = new KeyEntry();
|
||||
entry.date = new Date();
|
||||
|
||||
// Protect the encoding of the key
|
||||
passwordBytes = convertToBytes(password);
|
||||
keyProtector = new KeyProtector(passwordBytes);
|
||||
entry.protectedPrivKey = keyProtector.protect(key);
|
||||
|
||||
// clone the chain
|
||||
if ((chain != null) &&
|
||||
(chain.length != 0)) {
|
||||
entry.chain = chain.clone();
|
||||
} else {
|
||||
entry.chain = null;
|
||||
}
|
||||
|
||||
entries.put(convertAlias(alias), entry);
|
||||
}
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
throw new KeyStoreException("Key protection algorithm not found");
|
||||
} finally {
|
||||
if (passwordBytes != null)
|
||||
Arrays.fill(passwordBytes, (byte) 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the given key (that has already been protected) to the given
|
||||
* alias.
|
||||
*
|
||||
* <p>If the protected key is of type
|
||||
* <code>java.security.PrivateKey</code>, it must be accompanied by a
|
||||
* certificate chain certifying the corresponding public key. If the
|
||||
* underlying keystore implementation is of type <code>jks</code>,
|
||||
* <code>key</code> must be encoded as an
|
||||
* <code>EncryptedPrivateKeyInfo</code> as defined in the PKCS #8 standard.
|
||||
*
|
||||
* <p>If the given alias already exists, the keystore information
|
||||
* associated with it is overridden by the given key (and possibly
|
||||
* certificate chain).
|
||||
*
|
||||
* @param alias the alias name
|
||||
* @param key the key (in protected format) to be associated with the alias
|
||||
* @param chain the certificate chain for the corresponding public
|
||||
* key (only useful if the protected key is of type
|
||||
* <code>java.security.PrivateKey</code>).
|
||||
*
|
||||
* @exception KeyStoreException if this operation fails.
|
||||
*/
|
||||
public void engineSetKeyEntry(String alias, byte[] key,
|
||||
Certificate[] chain)
|
||||
throws KeyStoreException
|
||||
{
|
||||
synchronized(entries) {
|
||||
// key must be encoded as EncryptedPrivateKeyInfo as defined in
|
||||
// PKCS#8
|
||||
try {
|
||||
new EncryptedPrivateKeyInfo(key);
|
||||
} catch (IOException ioe) {
|
||||
throw new KeyStoreException("key is not encoded as "
|
||||
+ "EncryptedPrivateKeyInfo");
|
||||
}
|
||||
|
||||
KeyEntry entry = new KeyEntry();
|
||||
entry.date = new Date();
|
||||
|
||||
entry.protectedPrivKey = key.clone();
|
||||
if ((chain != null) &&
|
||||
(chain.length != 0)) {
|
||||
entry.chain = chain.clone();
|
||||
} else {
|
||||
entry.chain = null;
|
||||
}
|
||||
|
||||
entries.put(convertAlias(alias), entry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the given certificate to the given alias.
|
||||
*
|
||||
* <p>If the given alias already exists in this keystore and identifies a
|
||||
* <i>trusted certificate entry</i>, the certificate associated with it is
|
||||
* overridden by the given certificate.
|
||||
*
|
||||
* @param alias the alias name
|
||||
* @param cert the certificate
|
||||
*
|
||||
* @exception KeyStoreException if the given alias already exists and does
|
||||
* not identify a <i>trusted certificate entry</i>, or this operation
|
||||
* fails for some other reason.
|
||||
*/
|
||||
public void engineSetCertificateEntry(String alias, Certificate cert)
|
||||
throws KeyStoreException
|
||||
{
|
||||
synchronized(entries) {
|
||||
|
||||
Object entry = entries.get(convertAlias(alias));
|
||||
if ((entry != null) && (entry instanceof KeyEntry)) {
|
||||
throw new KeyStoreException
|
||||
("Cannot overwrite own certificate");
|
||||
}
|
||||
|
||||
TrustedCertEntry trustedCertEntry = new TrustedCertEntry();
|
||||
trustedCertEntry.cert = cert;
|
||||
trustedCertEntry.date = new Date();
|
||||
entries.put(convertAlias(alias), trustedCertEntry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the entry identified by the given alias from this keystore.
|
||||
*
|
||||
* @param alias the alias name
|
||||
*
|
||||
* @exception KeyStoreException if the entry cannot be removed.
|
||||
*/
|
||||
public void engineDeleteEntry(String alias)
|
||||
throws KeyStoreException
|
||||
{
|
||||
synchronized(entries) {
|
||||
entries.remove(convertAlias(alias));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all the alias names of this keystore.
|
||||
*
|
||||
* @return enumeration of the alias names
|
||||
*/
|
||||
public Enumeration<String> engineAliases() {
|
||||
return entries.keys();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given alias exists in this keystore.
|
||||
*
|
||||
* @param alias the alias name
|
||||
*
|
||||
* @return true if the alias exists, false otherwise
|
||||
*/
|
||||
public boolean engineContainsAlias(String alias) {
|
||||
return entries.containsKey(convertAlias(alias));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the number of entries in this keystore.
|
||||
*
|
||||
* @return the number of entries in this keystore
|
||||
*/
|
||||
public int engineSize() {
|
||||
return entries.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the entry identified by the given alias is a
|
||||
* <i>key entry</i>, and false otherwise.
|
||||
*
|
||||
* @return true if the entry identified by the given alias is a
|
||||
* <i>key entry</i>, false otherwise.
|
||||
*/
|
||||
public boolean engineIsKeyEntry(String alias) {
|
||||
Object entry = entries.get(convertAlias(alias));
|
||||
if ((entry != null) && (entry instanceof KeyEntry)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the entry identified by the given alias is a
|
||||
* <i>trusted certificate entry</i>, and false otherwise.
|
||||
*
|
||||
* @return true if the entry identified by the given alias is a
|
||||
* <i>trusted certificate entry</i>, false otherwise.
|
||||
*/
|
||||
public boolean engineIsCertificateEntry(String alias) {
|
||||
Object entry = entries.get(convertAlias(alias));
|
||||
if ((entry != null) && (entry instanceof TrustedCertEntry)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the (alias) name of the first keystore entry whose certificate
|
||||
* matches the given certificate.
|
||||
*
|
||||
* <p>This method attempts to match the given certificate with each
|
||||
* keystore entry. If the entry being considered
|
||||
* is a <i>trusted certificate entry</i>, the given certificate is
|
||||
* compared to that entry's certificate. If the entry being considered is
|
||||
* a <i>key entry</i>, the given certificate is compared to the first
|
||||
* element of that entry's certificate chain (if a chain exists).
|
||||
*
|
||||
* @param cert the certificate to match with.
|
||||
*
|
||||
* @return the (alias) name of the first entry with matching certificate,
|
||||
* or null if no such entry exists in this keystore.
|
||||
*/
|
||||
public String engineGetCertificateAlias(Certificate cert) {
|
||||
Certificate certElem;
|
||||
|
||||
for (Enumeration<String> e = entries.keys(); e.hasMoreElements(); ) {
|
||||
String alias = e.nextElement();
|
||||
Object entry = entries.get(alias);
|
||||
if (entry instanceof TrustedCertEntry) {
|
||||
certElem = ((TrustedCertEntry)entry).cert;
|
||||
} else if (((KeyEntry)entry).chain != null) {
|
||||
certElem = ((KeyEntry)entry).chain[0];
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if (certElem.equals(cert)) {
|
||||
return alias;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores this keystore to the given output stream, and protects its
|
||||
* integrity with the given password.
|
||||
*
|
||||
* @param stream the output stream to which this keystore is written.
|
||||
* @param password the password to generate the keystore integrity check
|
||||
*
|
||||
* @exception IOException if there was an I/O problem with data
|
||||
* @exception NoSuchAlgorithmException if the appropriate data integrity
|
||||
* algorithm could not be found
|
||||
* @exception CertificateException if any of the certificates included in
|
||||
* the keystore data could not be stored
|
||||
*/
|
||||
public void engineStore(OutputStream stream, char[] password)
|
||||
throws IOException, NoSuchAlgorithmException, CertificateException
|
||||
{
|
||||
synchronized(entries) {
|
||||
/*
|
||||
* KEYSTORE FORMAT:
|
||||
*
|
||||
* Magic number (big-endian integer),
|
||||
* Version of this file format (big-endian integer),
|
||||
*
|
||||
* Count (big-endian integer),
|
||||
* followed by "count" instances of either:
|
||||
*
|
||||
* {
|
||||
* tag=1 (big-endian integer),
|
||||
* alias (UTF string)
|
||||
* timestamp
|
||||
* encrypted private-key info according to PKCS #8
|
||||
* (integer length followed by encoding)
|
||||
* cert chain (integer count, then certs; for each cert,
|
||||
* integer length followed by encoding)
|
||||
* }
|
||||
*
|
||||
* or:
|
||||
*
|
||||
* {
|
||||
* tag=2 (big-endian integer)
|
||||
* alias (UTF string)
|
||||
* timestamp
|
||||
* cert (integer length followed by encoding)
|
||||
* }
|
||||
*
|
||||
* ended by a keyed SHA1 hash (bytes only) of
|
||||
* { password + whitener + preceding body }
|
||||
*/
|
||||
|
||||
// password is mandatory when storing
|
||||
if (password == null) {
|
||||
throw new IllegalArgumentException("password can't be null");
|
||||
}
|
||||
|
||||
byte[] encoded; // the certificate encoding
|
||||
|
||||
MessageDigest md = getPreKeyedHash(password);
|
||||
DataOutputStream dos
|
||||
= new DataOutputStream(new DigestOutputStream(stream, md));
|
||||
|
||||
dos.writeInt(MAGIC);
|
||||
// always write the latest version
|
||||
dos.writeInt(VERSION_2);
|
||||
|
||||
dos.writeInt(entries.size());
|
||||
|
||||
for (Enumeration<String> e = entries.keys(); e.hasMoreElements();) {
|
||||
|
||||
String alias = e.nextElement();
|
||||
Object entry = entries.get(alias);
|
||||
|
||||
if (entry instanceof KeyEntry) {
|
||||
|
||||
// Store this entry as a KeyEntry
|
||||
dos.writeInt(1);
|
||||
|
||||
// Write the alias
|
||||
dos.writeUTF(alias);
|
||||
|
||||
// Write the (entry creation) date
|
||||
dos.writeLong(((KeyEntry)entry).date.getTime());
|
||||
|
||||
// Write the protected private key
|
||||
dos.writeInt(((KeyEntry)entry).protectedPrivKey.length);
|
||||
dos.write(((KeyEntry)entry).protectedPrivKey);
|
||||
|
||||
// Write the certificate chain
|
||||
int chainLen;
|
||||
if (((KeyEntry)entry).chain == null) {
|
||||
chainLen = 0;
|
||||
} else {
|
||||
chainLen = ((KeyEntry)entry).chain.length;
|
||||
}
|
||||
dos.writeInt(chainLen);
|
||||
for (int i = 0; i < chainLen; i++) {
|
||||
encoded = ((KeyEntry)entry).chain[i].getEncoded();
|
||||
dos.writeUTF(((KeyEntry)entry).chain[i].getType());
|
||||
dos.writeInt(encoded.length);
|
||||
dos.write(encoded);
|
||||
}
|
||||
} else {
|
||||
|
||||
// Store this entry as a certificate
|
||||
dos.writeInt(2);
|
||||
|
||||
// Write the alias
|
||||
dos.writeUTF(alias);
|
||||
|
||||
// Write the (entry creation) date
|
||||
dos.writeLong(((TrustedCertEntry)entry).date.getTime());
|
||||
|
||||
// Write the trusted certificate
|
||||
encoded = ((TrustedCertEntry)entry).cert.getEncoded();
|
||||
dos.writeUTF(((TrustedCertEntry)entry).cert.getType());
|
||||
dos.writeInt(encoded.length);
|
||||
dos.write(encoded);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the keyed hash which is used to detect tampering with
|
||||
* the keystore (such as deleting or modifying key or
|
||||
* certificate entries).
|
||||
*/
|
||||
byte digest[] = md.digest();
|
||||
|
||||
dos.write(digest);
|
||||
dos.flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the keystore from the given input stream.
|
||||
*
|
||||
* <p>If a password is given, it is used to check the integrity of the
|
||||
* keystore data. Otherwise, the integrity of the keystore is not checked.
|
||||
*
|
||||
* @param stream the input stream from which the keystore is loaded
|
||||
* @param password the (optional) password used to check the integrity of
|
||||
* the keystore.
|
||||
*
|
||||
* @exception IOException if there is an I/O or format problem with the
|
||||
* keystore data
|
||||
* @exception NoSuchAlgorithmException if the algorithm used to check
|
||||
* the integrity of the keystore cannot be found
|
||||
* @exception CertificateException if any of the certificates in the
|
||||
* keystore could not be loaded
|
||||
*/
|
||||
public void engineLoad(InputStream stream, char[] password)
|
||||
throws IOException, NoSuchAlgorithmException, CertificateException
|
||||
{
|
||||
synchronized(entries) {
|
||||
DataInputStream dis;
|
||||
MessageDigest md = null;
|
||||
CertificateFactory cf = null;
|
||||
Hashtable<String, CertificateFactory> cfs = null;
|
||||
ByteArrayInputStream bais = null;
|
||||
byte[] encoded = null;
|
||||
int trustedKeyCount = 0, privateKeyCount = 0;
|
||||
|
||||
if (stream == null)
|
||||
return;
|
||||
|
||||
if (password != null) {
|
||||
md = getPreKeyedHash(password);
|
||||
dis = new DataInputStream(new DigestInputStream(stream, md));
|
||||
} else {
|
||||
dis = new DataInputStream(stream);
|
||||
}
|
||||
|
||||
// Body format: see store method
|
||||
|
||||
int xMagic = dis.readInt();
|
||||
int xVersion = dis.readInt();
|
||||
|
||||
if (xMagic!=MAGIC ||
|
||||
(xVersion!=VERSION_1 && xVersion!=VERSION_2)) {
|
||||
throw new IOException("Invalid keystore format");
|
||||
}
|
||||
|
||||
if (xVersion == VERSION_1) {
|
||||
cf = CertificateFactory.getInstance("X509");
|
||||
} else {
|
||||
// version 2
|
||||
cfs = new Hashtable<String, CertificateFactory>(3);
|
||||
}
|
||||
|
||||
entries.clear();
|
||||
int count = dis.readInt();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
int tag;
|
||||
String alias;
|
||||
|
||||
tag = dis.readInt();
|
||||
|
||||
if (tag == 1) { // private key entry
|
||||
privateKeyCount++;
|
||||
KeyEntry entry = new KeyEntry();
|
||||
|
||||
// Read the alias
|
||||
alias = dis.readUTF();
|
||||
|
||||
// Read the (entry creation) date
|
||||
entry.date = new Date(dis.readLong());
|
||||
|
||||
// Read the private key
|
||||
entry.protectedPrivKey =
|
||||
IOUtils.readExactlyNBytes(dis, dis.readInt());
|
||||
|
||||
// Read the certificate chain
|
||||
int numOfCerts = dis.readInt();
|
||||
if (numOfCerts > 0) {
|
||||
List<Certificate> certs = new ArrayList<>(
|
||||
numOfCerts > 10 ? 10 : numOfCerts);
|
||||
for (int j = 0; j < numOfCerts; j++) {
|
||||
if (xVersion == 2) {
|
||||
// read the certificate type, and instantiate a
|
||||
// certificate factory of that type (reuse
|
||||
// existing factory if possible)
|
||||
String certType = dis.readUTF();
|
||||
if (cfs.containsKey(certType)) {
|
||||
// reuse certificate factory
|
||||
cf = cfs.get(certType);
|
||||
} else {
|
||||
// create new certificate factory
|
||||
cf = CertificateFactory.getInstance(certType);
|
||||
// store the certificate factory so we can
|
||||
// reuse it later
|
||||
cfs.put(certType, cf);
|
||||
}
|
||||
}
|
||||
// instantiate the certificate
|
||||
encoded = IOUtils.readExactlyNBytes(dis, dis.readInt());
|
||||
bais = new ByteArrayInputStream(encoded);
|
||||
certs.add(cf.generateCertificate(bais));
|
||||
bais.close();
|
||||
}
|
||||
// We can be sure now that numOfCerts of certs are read
|
||||
entry.chain = certs.toArray(new Certificate[numOfCerts]);
|
||||
}
|
||||
|
||||
// Add the entry to the list
|
||||
entries.put(alias, entry);
|
||||
|
||||
} else if (tag == 2) { // trusted certificate entry
|
||||
trustedKeyCount++;
|
||||
TrustedCertEntry entry = new TrustedCertEntry();
|
||||
|
||||
// Read the alias
|
||||
alias = dis.readUTF();
|
||||
|
||||
// Read the (entry creation) date
|
||||
entry.date = new Date(dis.readLong());
|
||||
|
||||
// Read the trusted certificate
|
||||
if (xVersion == 2) {
|
||||
// read the certificate type, and instantiate a
|
||||
// certificate factory of that type (reuse
|
||||
// existing factory if possible)
|
||||
String certType = dis.readUTF();
|
||||
if (cfs.containsKey(certType)) {
|
||||
// reuse certificate factory
|
||||
cf = cfs.get(certType);
|
||||
} else {
|
||||
// create new certificate factory
|
||||
cf = CertificateFactory.getInstance(certType);
|
||||
// store the certificate factory so we can
|
||||
// reuse it later
|
||||
cfs.put(certType, cf);
|
||||
}
|
||||
}
|
||||
encoded = IOUtils.readExactlyNBytes(dis, dis.readInt());
|
||||
bais = new ByteArrayInputStream(encoded);
|
||||
entry.cert = cf.generateCertificate(bais);
|
||||
bais.close();
|
||||
|
||||
// Add the entry to the list
|
||||
entries.put(alias, entry);
|
||||
|
||||
} else {
|
||||
throw new IOException("Unrecognized keystore entry: " +
|
||||
tag);
|
||||
}
|
||||
}
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("JavaKeyStore load: private key count: " +
|
||||
privateKeyCount + ". trusted key count: " + trustedKeyCount);
|
||||
}
|
||||
|
||||
/*
|
||||
* If a password has been provided, we check the keyed digest
|
||||
* at the end. If this check fails, the store has been tampered
|
||||
* with
|
||||
*/
|
||||
if (password != null) {
|
||||
byte computed[], actual[];
|
||||
computed = md.digest();
|
||||
actual = IOUtils.readExactlyNBytes(dis, computed.length);
|
||||
if (!MessageDigest.isEqual(computed, actual)) {
|
||||
Throwable t = new UnrecoverableKeyException
|
||||
("Password verification failed");
|
||||
throw (IOException) new IOException
|
||||
("Keystore was tampered with, or "
|
||||
+ "password was incorrect").initCause(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To guard against tampering with the keystore, we append a keyed
|
||||
* hash with a bit of whitener.
|
||||
*/
|
||||
private MessageDigest getPreKeyedHash(char[] password)
|
||||
throws NoSuchAlgorithmException, UnsupportedEncodingException
|
||||
{
|
||||
|
||||
MessageDigest md = MessageDigest.getInstance("SHA");
|
||||
byte[] passwdBytes = convertToBytes(password);
|
||||
md.update(passwdBytes);
|
||||
Arrays.fill(passwdBytes, (byte) 0x00);
|
||||
md.update("Mighty Aphrodite".getBytes("UTF8"));
|
||||
return md;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to convert char[] to byte[]
|
||||
*/
|
||||
|
||||
private byte[] convertToBytes(char[] password) {
|
||||
int i, j;
|
||||
byte[] passwdBytes = new byte[password.length * 2];
|
||||
for (i=0, j=0; i<password.length; i++) {
|
||||
passwdBytes[j++] = (byte)(password[i] >> 8);
|
||||
passwdBytes[j++] = (byte)password[i];
|
||||
}
|
||||
return passwdBytes;
|
||||
}
|
||||
}
|
||||
328
jdkSrc/jdk8/sun/security/provider/KeyProtector.java
Normal file
328
jdkSrc/jdk8/sun/security/provider/KeyProtector.java
Normal file
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.Key;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.util.*;
|
||||
|
||||
import sun.security.pkcs.PKCS8Key;
|
||||
import sun.security.pkcs.EncryptedPrivateKeyInfo;
|
||||
import sun.security.x509.AlgorithmId;
|
||||
import sun.security.util.ObjectIdentifier;
|
||||
import sun.security.util.DerValue;
|
||||
|
||||
/**
|
||||
* This is an implementation of a Sun proprietary, exportable algorithm
|
||||
* intended for use when protecting (or recovering the cleartext version of)
|
||||
* sensitive keys.
|
||||
* This algorithm is not intended as a general purpose cipher.
|
||||
*
|
||||
* This is how the algorithm works for key protection:
|
||||
*
|
||||
* p - user password
|
||||
* s - random salt
|
||||
* X - xor key
|
||||
* P - to-be-protected key
|
||||
* Y - protected key
|
||||
* R - what gets stored in the keystore
|
||||
*
|
||||
* Step 1:
|
||||
* Take the user's password, append a random salt (of fixed size) to it,
|
||||
* and hash it: d1 = digest(p, s)
|
||||
* Store d1 in X.
|
||||
*
|
||||
* Step 2:
|
||||
* Take the user's password, append the digest result from the previous step,
|
||||
* and hash it: dn = digest(p, dn-1).
|
||||
* Store dn in X (append it to the previously stored digests).
|
||||
* Repeat this step until the length of X matches the length of the private key
|
||||
* P.
|
||||
*
|
||||
* Step 3:
|
||||
* XOR X and P, and store the result in Y: Y = X XOR P.
|
||||
*
|
||||
* Step 4:
|
||||
* Store s, Y, and digest(p, P) in the result buffer R:
|
||||
* R = s + Y + digest(p, P), where "+" denotes concatenation.
|
||||
* (NOTE: digest(p, P) is stored in the result buffer, so that when the key is
|
||||
* recovered, we can check if the recovered key indeed matches the original
|
||||
* key.) R is stored in the keystore.
|
||||
*
|
||||
* The protected key is recovered as follows:
|
||||
*
|
||||
* Step1 and Step2 are the same as above, except that the salt is not randomly
|
||||
* generated, but taken from the result R of step 4 (the first length(s)
|
||||
* bytes).
|
||||
*
|
||||
* Step 3 (XOR operation) yields the plaintext key.
|
||||
*
|
||||
* Then concatenate the password with the recovered key, and compare with the
|
||||
* last length(digest(p, P)) bytes of R. If they match, the recovered key is
|
||||
* indeed the same key as the original key.
|
||||
*
|
||||
* @author Jan Luehe
|
||||
*
|
||||
*
|
||||
* @see java.security.KeyStore
|
||||
* @see JavaKeyStore
|
||||
* @see KeyTool
|
||||
*
|
||||
* @since 1.2
|
||||
*/
|
||||
|
||||
final class KeyProtector {
|
||||
|
||||
private static final int SALT_LEN = 20; // the salt length
|
||||
private static final String DIGEST_ALG = "SHA";
|
||||
private static final int DIGEST_LEN = 20;
|
||||
|
||||
// defined by JavaSoft
|
||||
private static final String KEY_PROTECTOR_OID = "1.3.6.1.4.1.42.2.17.1.1";
|
||||
|
||||
// The password used for protecting/recovering keys passed through this
|
||||
// key protector. We store it as a byte array, so that we can digest it.
|
||||
private byte[] passwdBytes;
|
||||
|
||||
private MessageDigest md;
|
||||
|
||||
|
||||
/**
|
||||
* Creates an instance of this class, and initializes it with the given
|
||||
* password.
|
||||
*/
|
||||
public KeyProtector(byte[] passwordBytes)
|
||||
throws NoSuchAlgorithmException
|
||||
{
|
||||
if (passwordBytes == null) {
|
||||
throw new IllegalArgumentException("password can't be null");
|
||||
}
|
||||
md = MessageDigest.getInstance(DIGEST_ALG);
|
||||
this.passwdBytes = passwordBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the password bytes of this key protector are
|
||||
* set to zero when there are no more references to it.
|
||||
*/
|
||||
protected void finalize() {
|
||||
if (passwdBytes != null) {
|
||||
Arrays.fill(passwdBytes, (byte)0x00);
|
||||
passwdBytes = null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Protects the given plaintext key, using the password provided at
|
||||
* construction time.
|
||||
*/
|
||||
public byte[] protect(Key key) throws KeyStoreException
|
||||
{
|
||||
int i;
|
||||
int numRounds;
|
||||
byte[] digest;
|
||||
int xorOffset; // offset in xorKey where next digest will be stored
|
||||
int encrKeyOffset = 0;
|
||||
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException("plaintext key can't be null");
|
||||
}
|
||||
|
||||
if (!"PKCS#8".equalsIgnoreCase(key.getFormat())) {
|
||||
throw new KeyStoreException(
|
||||
"Cannot get key bytes, not PKCS#8 encoded");
|
||||
}
|
||||
|
||||
byte[] plainKey = key.getEncoded();
|
||||
if (plainKey == null) {
|
||||
throw new KeyStoreException(
|
||||
"Cannot get key bytes, encoding not supported");
|
||||
}
|
||||
|
||||
// Determine the number of digest rounds
|
||||
numRounds = plainKey.length / DIGEST_LEN;
|
||||
if ((plainKey.length % DIGEST_LEN) != 0)
|
||||
numRounds++;
|
||||
|
||||
// Create a random salt
|
||||
byte[] salt = new byte[SALT_LEN];
|
||||
SecureRandom random = new SecureRandom();
|
||||
random.nextBytes(salt);
|
||||
|
||||
// Set up the byte array which will be XORed with "plainKey"
|
||||
byte[] xorKey = new byte[plainKey.length];
|
||||
|
||||
// Compute the digests, and store them in "xorKey"
|
||||
for (i = 0, xorOffset = 0, digest = salt;
|
||||
i < numRounds;
|
||||
i++, xorOffset += DIGEST_LEN) {
|
||||
md.update(passwdBytes);
|
||||
md.update(digest);
|
||||
digest = md.digest();
|
||||
md.reset();
|
||||
// Copy the digest into "xorKey"
|
||||
if (i < numRounds - 1) {
|
||||
System.arraycopy(digest, 0, xorKey, xorOffset,
|
||||
digest.length);
|
||||
} else {
|
||||
System.arraycopy(digest, 0, xorKey, xorOffset,
|
||||
xorKey.length - xorOffset);
|
||||
}
|
||||
}
|
||||
|
||||
// XOR "plainKey" with "xorKey", and store the result in "tmpKey"
|
||||
byte[] tmpKey = new byte[plainKey.length];
|
||||
for (i = 0; i < tmpKey.length; i++) {
|
||||
tmpKey[i] = (byte)(plainKey[i] ^ xorKey[i]);
|
||||
}
|
||||
|
||||
// Store salt and "tmpKey" in "encrKey"
|
||||
byte[] encrKey = new byte[salt.length + tmpKey.length + DIGEST_LEN];
|
||||
System.arraycopy(salt, 0, encrKey, encrKeyOffset, salt.length);
|
||||
encrKeyOffset += salt.length;
|
||||
System.arraycopy(tmpKey, 0, encrKey, encrKeyOffset, tmpKey.length);
|
||||
encrKeyOffset += tmpKey.length;
|
||||
|
||||
// Append digest(password, plainKey) as an integrity check to "encrKey"
|
||||
md.update(passwdBytes);
|
||||
Arrays.fill(passwdBytes, (byte)0x00);
|
||||
passwdBytes = null;
|
||||
md.update(plainKey);
|
||||
digest = md.digest();
|
||||
md.reset();
|
||||
System.arraycopy(digest, 0, encrKey, encrKeyOffset, digest.length);
|
||||
|
||||
// wrap the protected private key in a PKCS#8-style
|
||||
// EncryptedPrivateKeyInfo, and returns its encoding
|
||||
AlgorithmId encrAlg;
|
||||
try {
|
||||
encrAlg = new AlgorithmId(new ObjectIdentifier(KEY_PROTECTOR_OID));
|
||||
return new EncryptedPrivateKeyInfo(encrAlg,encrKey).getEncoded();
|
||||
} catch (IOException ioe) {
|
||||
throw new KeyStoreException(ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Recovers the plaintext version of the given key (in protected format),
|
||||
* using the password provided at construction time.
|
||||
*/
|
||||
public Key recover(EncryptedPrivateKeyInfo encrInfo)
|
||||
throws UnrecoverableKeyException
|
||||
{
|
||||
int i;
|
||||
byte[] digest;
|
||||
int numRounds;
|
||||
int xorOffset; // offset in xorKey where next digest will be stored
|
||||
int encrKeyLen; // the length of the encrpyted key
|
||||
|
||||
// do we support the algorithm?
|
||||
AlgorithmId encrAlg = encrInfo.getAlgorithm();
|
||||
if (!(encrAlg.getOID().toString().equals(KEY_PROTECTOR_OID))) {
|
||||
throw new UnrecoverableKeyException("Unsupported key protection "
|
||||
+ "algorithm");
|
||||
}
|
||||
|
||||
byte[] protectedKey = encrInfo.getEncryptedData();
|
||||
|
||||
/*
|
||||
* Get the salt associated with this key (the first SALT_LEN bytes of
|
||||
* <code>protectedKey</code>)
|
||||
*/
|
||||
byte[] salt = new byte[SALT_LEN];
|
||||
System.arraycopy(protectedKey, 0, salt, 0, SALT_LEN);
|
||||
|
||||
// Determine the number of digest rounds
|
||||
encrKeyLen = protectedKey.length - SALT_LEN - DIGEST_LEN;
|
||||
numRounds = encrKeyLen / DIGEST_LEN;
|
||||
if ((encrKeyLen % DIGEST_LEN) != 0) numRounds++;
|
||||
|
||||
// Get the encrypted key portion and store it in "encrKey"
|
||||
byte[] encrKey = new byte[encrKeyLen];
|
||||
System.arraycopy(protectedKey, SALT_LEN, encrKey, 0, encrKeyLen);
|
||||
|
||||
// Set up the byte array which will be XORed with "encrKey"
|
||||
byte[] xorKey = new byte[encrKey.length];
|
||||
|
||||
// Compute the digests, and store them in "xorKey"
|
||||
for (i = 0, xorOffset = 0, digest = salt;
|
||||
i < numRounds;
|
||||
i++, xorOffset += DIGEST_LEN) {
|
||||
md.update(passwdBytes);
|
||||
md.update(digest);
|
||||
digest = md.digest();
|
||||
md.reset();
|
||||
// Copy the digest into "xorKey"
|
||||
if (i < numRounds - 1) {
|
||||
System.arraycopy(digest, 0, xorKey, xorOffset,
|
||||
digest.length);
|
||||
} else {
|
||||
System.arraycopy(digest, 0, xorKey, xorOffset,
|
||||
xorKey.length - xorOffset);
|
||||
}
|
||||
}
|
||||
|
||||
// XOR "encrKey" with "xorKey", and store the result in "plainKey"
|
||||
byte[] plainKey = new byte[encrKey.length];
|
||||
for (i = 0; i < plainKey.length; i++) {
|
||||
plainKey[i] = (byte)(encrKey[i] ^ xorKey[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the integrity of the recovered key by concatenating it with
|
||||
* the password, digesting the concatenation, and comparing the
|
||||
* result of the digest operation with the digest provided at the end
|
||||
* of <code>protectedKey</code>. If the two digest values are
|
||||
* different, throw an exception.
|
||||
*/
|
||||
md.update(passwdBytes);
|
||||
Arrays.fill(passwdBytes, (byte)0x00);
|
||||
passwdBytes = null;
|
||||
md.update(plainKey);
|
||||
digest = md.digest();
|
||||
md.reset();
|
||||
for (i = 0; i < digest.length; i++) {
|
||||
if (digest[i] != protectedKey[SALT_LEN + encrKeyLen + i]) {
|
||||
throw new UnrecoverableKeyException("Cannot recover key");
|
||||
}
|
||||
}
|
||||
|
||||
// The parseKey() method of PKCS8Key parses the key
|
||||
// algorithm and instantiates the appropriate key factory,
|
||||
// which in turn parses the key material.
|
||||
try {
|
||||
return PKCS8Key.parseKey(new DerValue(plainKey));
|
||||
} catch (IOException ioe) {
|
||||
throw new UnrecoverableKeyException(ioe.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
279
jdkSrc/jdk8/sun/security/provider/KeyStoreDelegator.java
Normal file
279
jdkSrc/jdk8/sun/security/provider/KeyStoreDelegator.java
Normal file
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.io.*;
|
||||
import java.security.*;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.*;
|
||||
|
||||
import sun.security.util.Debug;
|
||||
|
||||
/**
|
||||
* This class delegates to a primary or secondary keystore implementation.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
|
||||
class KeyStoreDelegator extends KeyStoreSpi {
|
||||
|
||||
private static final String KEYSTORE_TYPE_COMPAT = "keystore.type.compat";
|
||||
private static final Debug debug = Debug.getInstance("keystore");
|
||||
|
||||
private final String primaryType; // the primary keystore's type
|
||||
private final String secondaryType; // the secondary keystore's type
|
||||
private final Class<? extends KeyStoreSpi> primaryKeyStore;
|
||||
// the primary keystore's class
|
||||
private final Class<? extends KeyStoreSpi> secondaryKeyStore;
|
||||
// the secondary keystore's class
|
||||
private String type; // the delegate's type
|
||||
private KeyStoreSpi keystore; // the delegate
|
||||
private boolean compatModeEnabled = true;
|
||||
|
||||
public KeyStoreDelegator(
|
||||
String primaryType,
|
||||
Class<? extends KeyStoreSpi> primaryKeyStore,
|
||||
String secondaryType,
|
||||
Class<? extends KeyStoreSpi> secondaryKeyStore) {
|
||||
|
||||
// Check whether compatibility mode has been disabled
|
||||
// (Use inner-class instead of lambda to avoid init/ClassLoader problem)
|
||||
compatModeEnabled = "true".equalsIgnoreCase(
|
||||
AccessController.doPrivileged(
|
||||
new PrivilegedAction<String>() {
|
||||
public String run() {
|
||||
return Security.getProperty(KEYSTORE_TYPE_COMPAT);
|
||||
}
|
||||
}
|
||||
));
|
||||
|
||||
if (compatModeEnabled) {
|
||||
this.primaryType = primaryType;
|
||||
this.secondaryType = secondaryType;
|
||||
this.primaryKeyStore = primaryKeyStore;
|
||||
this.secondaryKeyStore = secondaryKeyStore;
|
||||
} else {
|
||||
this.primaryType = primaryType;
|
||||
this.secondaryType = null;
|
||||
this.primaryKeyStore = primaryKeyStore;
|
||||
this.secondaryKeyStore = null;
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("WARNING: compatibility mode disabled for " +
|
||||
primaryType + " and " + secondaryType + " keystore types");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Key engineGetKey(String alias, char[] password)
|
||||
throws NoSuchAlgorithmException, UnrecoverableKeyException {
|
||||
return keystore.engineGetKey(alias, password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Certificate[] engineGetCertificateChain(String alias) {
|
||||
return keystore.engineGetCertificateChain(alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Certificate engineGetCertificate(String alias) {
|
||||
return keystore.engineGetCertificate(alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date engineGetCreationDate(String alias) {
|
||||
return keystore.engineGetCreationDate(alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void engineSetKeyEntry(String alias, Key key, char[] password,
|
||||
Certificate[] chain) throws KeyStoreException {
|
||||
keystore.engineSetKeyEntry(alias, key, password, chain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain)
|
||||
throws KeyStoreException {
|
||||
keystore.engineSetKeyEntry(alias, key, chain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void engineSetCertificateEntry(String alias, Certificate cert)
|
||||
throws KeyStoreException {
|
||||
keystore.engineSetCertificateEntry(alias, cert);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void engineDeleteEntry(String alias) throws KeyStoreException {
|
||||
keystore.engineDeleteEntry(alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> engineAliases() {
|
||||
return keystore.engineAliases();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean engineContainsAlias(String alias) {
|
||||
return keystore.engineContainsAlias(alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int engineSize() {
|
||||
return keystore.engineSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean engineIsKeyEntry(String alias) {
|
||||
return keystore.engineIsKeyEntry(alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean engineIsCertificateEntry(String alias) {
|
||||
return keystore.engineIsCertificateEntry(alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String engineGetCertificateAlias(Certificate cert) {
|
||||
return keystore.engineGetCertificateAlias(cert);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyStore.Entry engineGetEntry(String alias,
|
||||
KeyStore.ProtectionParameter protParam)
|
||||
throws KeyStoreException, NoSuchAlgorithmException,
|
||||
UnrecoverableEntryException {
|
||||
return keystore.engineGetEntry(alias, protParam);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void engineSetEntry(String alias, KeyStore.Entry entry,
|
||||
KeyStore.ProtectionParameter protParam)
|
||||
throws KeyStoreException {
|
||||
keystore.engineSetEntry(alias, entry, protParam);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean engineEntryInstanceOf(String alias,
|
||||
Class<? extends KeyStore.Entry> entryClass) {
|
||||
return keystore.engineEntryInstanceOf(alias, entryClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void engineStore(OutputStream stream, char[] password)
|
||||
throws IOException, NoSuchAlgorithmException, CertificateException {
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("Storing keystore in " + type + " format");
|
||||
}
|
||||
keystore.engineStore(stream, password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void engineLoad(InputStream stream, char[] password)
|
||||
throws IOException, NoSuchAlgorithmException, CertificateException {
|
||||
|
||||
// A new keystore is always created in the primary keystore format
|
||||
if (stream == null || !compatModeEnabled) {
|
||||
try {
|
||||
keystore = primaryKeyStore.newInstance();
|
||||
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
// can safely ignore
|
||||
}
|
||||
type = primaryType;
|
||||
|
||||
if (debug != null && stream == null) {
|
||||
debug.println("Creating a new keystore in " + type + " format");
|
||||
}
|
||||
keystore.engineLoad(stream, password);
|
||||
|
||||
} else {
|
||||
// First try the primary keystore then try the secondary keystore
|
||||
InputStream bufferedStream = new BufferedInputStream(stream);
|
||||
bufferedStream.mark(Integer.MAX_VALUE);
|
||||
try {
|
||||
keystore = primaryKeyStore.newInstance();
|
||||
type = primaryType;
|
||||
keystore.engineLoad(bufferedStream, password);
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
// incorrect password
|
||||
if (e instanceof IOException &&
|
||||
e.getCause() instanceof UnrecoverableKeyException) {
|
||||
throw (IOException)e;
|
||||
}
|
||||
|
||||
try {
|
||||
keystore = secondaryKeyStore.newInstance();
|
||||
type = secondaryType;
|
||||
bufferedStream.reset();
|
||||
keystore.engineLoad(bufferedStream, password);
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("WARNING: switching from " +
|
||||
primaryType + " to " + secondaryType +
|
||||
" keystore file format has altered the " +
|
||||
"keystore security level");
|
||||
}
|
||||
|
||||
} catch (InstantiationException |
|
||||
IllegalAccessException e2) {
|
||||
// can safely ignore
|
||||
|
||||
} catch (IOException |
|
||||
NoSuchAlgorithmException |
|
||||
CertificateException e3) {
|
||||
|
||||
// incorrect password
|
||||
if (e3 instanceof IOException &&
|
||||
e3.getCause() instanceof
|
||||
UnrecoverableKeyException) {
|
||||
throw (IOException)e3;
|
||||
}
|
||||
// rethrow the outer exception
|
||||
if (e instanceof IOException) {
|
||||
throw (IOException)e;
|
||||
} else if (e instanceof CertificateException) {
|
||||
throw (CertificateException)e;
|
||||
} else if (e instanceof NoSuchAlgorithmException) {
|
||||
throw (NoSuchAlgorithmException)e;
|
||||
} else if (e instanceof RuntimeException){
|
||||
throw (RuntimeException)e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("Loaded a keystore in " + type + " format");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
147
jdkSrc/jdk8/sun/security/provider/MD2.java
Normal file
147
jdkSrc/jdk8/sun/security/provider/MD2.java
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Implementation for the MD2 algorithm, see RFC1319. It is very slow and
|
||||
* not particular secure. It is only supported to be able to verify
|
||||
* RSA/Verisign root certificates signed using MD2withRSA. It should not
|
||||
* be used for anything else.
|
||||
*
|
||||
* @since 1.5
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public final class MD2 extends DigestBase {
|
||||
|
||||
// state, 48 ints
|
||||
private int[] X;
|
||||
|
||||
// checksum, 16 ints. they are really bytes, but byte arithmetic in
|
||||
// the JVM is much slower that int arithmetic.
|
||||
private int[] C;
|
||||
|
||||
// temporary store for checksum C during final digest
|
||||
private byte[] cBytes;
|
||||
|
||||
/**
|
||||
* Create a new MD2 digest. Called by the JCA framework
|
||||
*/
|
||||
public MD2() {
|
||||
super("MD2", 16, 16);
|
||||
X = new int[48];
|
||||
C = new int[16];
|
||||
cBytes = new byte[16];
|
||||
}
|
||||
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
MD2 copy = (MD2) super.clone();
|
||||
copy.X = copy.X.clone();
|
||||
copy.C = copy.C.clone();
|
||||
copy.cBytes = new byte[16];
|
||||
return copy;
|
||||
}
|
||||
|
||||
// reset state and checksum
|
||||
void implReset() {
|
||||
Arrays.fill(X, 0);
|
||||
Arrays.fill(C, 0);
|
||||
}
|
||||
|
||||
// finish the digest
|
||||
void implDigest(byte[] out, int ofs) {
|
||||
int padValue = 16 - ((int)bytesProcessed & 15);
|
||||
engineUpdate(PADDING[padValue], 0, padValue);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
cBytes[i] = (byte)C[i];
|
||||
}
|
||||
implCompress(cBytes, 0);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
out[ofs + i] = (byte)X[i];
|
||||
}
|
||||
}
|
||||
|
||||
// one iteration of the compression function
|
||||
void implCompress(byte[] b, int ofs) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
int k = b[ofs + i] & 0xff;
|
||||
X[16 + i] = k;
|
||||
X[32 + i] = k ^ X[i];
|
||||
}
|
||||
|
||||
// update the checksum
|
||||
int t = C[15];
|
||||
for (int i = 0; i < 16; i++) {
|
||||
t = (C[i] ^= S[X[16 + i] ^ t]);
|
||||
}
|
||||
|
||||
t = 0;
|
||||
for (int i = 0; i < 18; i++) {
|
||||
for (int j = 0; j < 48; j++) {
|
||||
t = (X[j] ^= S[t]);
|
||||
}
|
||||
t = (t + i) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
// substitution table derived from Pi. Copied from the RFC.
|
||||
private final static int[] S = new int[] {
|
||||
41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
|
||||
19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
|
||||
76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
|
||||
138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
|
||||
245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
|
||||
148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
|
||||
39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
|
||||
181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
|
||||
150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
|
||||
112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
|
||||
96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
|
||||
85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
|
||||
234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
|
||||
129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
|
||||
8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
|
||||
203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
|
||||
166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
|
||||
31, 26, 219, 153, 141, 51, 159, 17, 131, 20,
|
||||
};
|
||||
|
||||
// digest padding. 17 element array.
|
||||
// padding[0] is null
|
||||
// padding[i] is an array of i time the byte value i (i = 1..16)
|
||||
private final static byte[][] PADDING;
|
||||
|
||||
static {
|
||||
PADDING = new byte[17][];
|
||||
for (int i = 1; i < 17; i++) {
|
||||
byte[] b = new byte[i];
|
||||
Arrays.fill(b, (byte)i);
|
||||
PADDING[i] = b;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
229
jdkSrc/jdk8/sun/security/provider/MD4.java
Normal file
229
jdkSrc/jdk8/sun/security/provider/MD4.java
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.security.*;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static sun.security.provider.ByteArrayAccess.*;
|
||||
|
||||
/**
|
||||
* The MD4 class is used to compute an MD4 message digest over a given
|
||||
* buffer of bytes. It is an implementation of the RSA Data Security Inc
|
||||
* MD4 algorithim as described in internet RFC 1320.
|
||||
*
|
||||
* <p>The MD4 algorithm is very weak and should not be used unless it is
|
||||
* unavoidable. Therefore, it is not registered in our standard providers. To
|
||||
* obtain an implementation, call the static getInstance() method in this
|
||||
* class.
|
||||
*
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public final class MD4 extends DigestBase {
|
||||
|
||||
// state of this object
|
||||
private int[] state;
|
||||
// temporary buffer, used by implCompress()
|
||||
private int[] x;
|
||||
|
||||
// rotation constants
|
||||
private static final int S11 = 3;
|
||||
private static final int S12 = 7;
|
||||
private static final int S13 = 11;
|
||||
private static final int S14 = 19;
|
||||
private static final int S21 = 3;
|
||||
private static final int S22 = 5;
|
||||
private static final int S23 = 9;
|
||||
private static final int S24 = 13;
|
||||
private static final int S31 = 3;
|
||||
private static final int S32 = 9;
|
||||
private static final int S33 = 11;
|
||||
private static final int S34 = 15;
|
||||
|
||||
private final static Provider md4Provider;
|
||||
|
||||
static {
|
||||
md4Provider = new Provider("MD4Provider", 1.8d, "MD4 MessageDigest") {
|
||||
private static final long serialVersionUID = -8850464997518327965L;
|
||||
};
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
md4Provider.put("MessageDigest.MD4", "sun.security.provider.MD4");
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static MessageDigest getInstance() {
|
||||
try {
|
||||
return MessageDigest.getInstance("MD4", md4Provider);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// should never occur
|
||||
throw new ProviderException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Standard constructor, creates a new MD4 instance.
|
||||
public MD4() {
|
||||
super("MD4", 16, 64);
|
||||
state = new int[4];
|
||||
x = new int[16];
|
||||
resetHashes();
|
||||
}
|
||||
|
||||
// clone this object
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
MD4 copy = (MD4) super.clone();
|
||||
copy.state = copy.state.clone();
|
||||
copy.x = new int[16];
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the state of this object.
|
||||
*/
|
||||
void implReset() {
|
||||
// Load magic initialization constants.
|
||||
resetHashes();
|
||||
// clear out old data
|
||||
Arrays.fill(x, 0);
|
||||
}
|
||||
|
||||
private void resetHashes() {
|
||||
state[0] = 0x67452301;
|
||||
state[1] = 0xefcdab89;
|
||||
state[2] = 0x98badcfe;
|
||||
state[3] = 0x10325476;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the final computations, any buffered bytes are added
|
||||
* to the digest, the count is added to the digest, and the resulting
|
||||
* digest is stored.
|
||||
*/
|
||||
void implDigest(byte[] out, int ofs) {
|
||||
long bitsProcessed = bytesProcessed << 3;
|
||||
|
||||
int index = (int)bytesProcessed & 0x3f;
|
||||
int padLen = (index < 56) ? (56 - index) : (120 - index);
|
||||
engineUpdate(padding, 0, padLen);
|
||||
|
||||
i2bLittle4((int)bitsProcessed, buffer, 56);
|
||||
i2bLittle4((int)(bitsProcessed >>> 32), buffer, 60);
|
||||
implCompress(buffer, 0);
|
||||
|
||||
i2bLittle(state, 0, out, ofs, 16);
|
||||
}
|
||||
|
||||
private static int FF(int a, int b, int c, int d, int x, int s) {
|
||||
a += ((b & c) | ((~b) & d)) + x;
|
||||
return ((a << s) | (a >>> (32 - s)));
|
||||
}
|
||||
|
||||
private static int GG(int a, int b, int c, int d, int x, int s) {
|
||||
a += ((b & c) | (b & d) | (c & d)) + x + 0x5a827999;
|
||||
return ((a << s) | (a >>> (32 - s)));
|
||||
}
|
||||
|
||||
private static int HH(int a, int b, int c, int d, int x, int s) {
|
||||
a += ((b ^ c) ^ d) + x + 0x6ed9eba1;
|
||||
return ((a << s) | (a >>> (32 - s)));
|
||||
}
|
||||
|
||||
/**
|
||||
* This is where the functions come together as the generic MD4
|
||||
* transformation operation. It consumes sixteen
|
||||
* bytes from the buffer, beginning at the specified offset.
|
||||
*/
|
||||
void implCompress(byte[] buf, int ofs) {
|
||||
b2iLittle64(buf, ofs, x);
|
||||
|
||||
int a = state[0];
|
||||
int b = state[1];
|
||||
int c = state[2];
|
||||
int d = state[3];
|
||||
|
||||
/* Round 1 */
|
||||
a = FF (a, b, c, d, x[ 0], S11); /* 1 */
|
||||
d = FF (d, a, b, c, x[ 1], S12); /* 2 */
|
||||
c = FF (c, d, a, b, x[ 2], S13); /* 3 */
|
||||
b = FF (b, c, d, a, x[ 3], S14); /* 4 */
|
||||
a = FF (a, b, c, d, x[ 4], S11); /* 5 */
|
||||
d = FF (d, a, b, c, x[ 5], S12); /* 6 */
|
||||
c = FF (c, d, a, b, x[ 6], S13); /* 7 */
|
||||
b = FF (b, c, d, a, x[ 7], S14); /* 8 */
|
||||
a = FF (a, b, c, d, x[ 8], S11); /* 9 */
|
||||
d = FF (d, a, b, c, x[ 9], S12); /* 10 */
|
||||
c = FF (c, d, a, b, x[10], S13); /* 11 */
|
||||
b = FF (b, c, d, a, x[11], S14); /* 12 */
|
||||
a = FF (a, b, c, d, x[12], S11); /* 13 */
|
||||
d = FF (d, a, b, c, x[13], S12); /* 14 */
|
||||
c = FF (c, d, a, b, x[14], S13); /* 15 */
|
||||
b = FF (b, c, d, a, x[15], S14); /* 16 */
|
||||
|
||||
/* Round 2 */
|
||||
a = GG (a, b, c, d, x[ 0], S21); /* 17 */
|
||||
d = GG (d, a, b, c, x[ 4], S22); /* 18 */
|
||||
c = GG (c, d, a, b, x[ 8], S23); /* 19 */
|
||||
b = GG (b, c, d, a, x[12], S24); /* 20 */
|
||||
a = GG (a, b, c, d, x[ 1], S21); /* 21 */
|
||||
d = GG (d, a, b, c, x[ 5], S22); /* 22 */
|
||||
c = GG (c, d, a, b, x[ 9], S23); /* 23 */
|
||||
b = GG (b, c, d, a, x[13], S24); /* 24 */
|
||||
a = GG (a, b, c, d, x[ 2], S21); /* 25 */
|
||||
d = GG (d, a, b, c, x[ 6], S22); /* 26 */
|
||||
c = GG (c, d, a, b, x[10], S23); /* 27 */
|
||||
b = GG (b, c, d, a, x[14], S24); /* 28 */
|
||||
a = GG (a, b, c, d, x[ 3], S21); /* 29 */
|
||||
d = GG (d, a, b, c, x[ 7], S22); /* 30 */
|
||||
c = GG (c, d, a, b, x[11], S23); /* 31 */
|
||||
b = GG (b, c, d, a, x[15], S24); /* 32 */
|
||||
|
||||
/* Round 3 */
|
||||
a = HH (a, b, c, d, x[ 0], S31); /* 33 */
|
||||
d = HH (d, a, b, c, x[ 8], S32); /* 34 */
|
||||
c = HH (c, d, a, b, x[ 4], S33); /* 35 */
|
||||
b = HH (b, c, d, a, x[12], S34); /* 36 */
|
||||
a = HH (a, b, c, d, x[ 2], S31); /* 37 */
|
||||
d = HH (d, a, b, c, x[10], S32); /* 38 */
|
||||
c = HH (c, d, a, b, x[ 6], S33); /* 39 */
|
||||
b = HH (b, c, d, a, x[14], S34); /* 40 */
|
||||
a = HH (a, b, c, d, x[ 1], S31); /* 41 */
|
||||
d = HH (d, a, b, c, x[ 9], S32); /* 42 */
|
||||
c = HH (c, d, a, b, x[ 5], S33); /* 43 */
|
||||
b = HH (b, c, d, a, x[13], S34); /* 44 */
|
||||
a = HH (a, b, c, d, x[ 3], S31); /* 45 */
|
||||
d = HH (d, a, b, c, x[11], S32); /* 46 */
|
||||
c = HH (c, d, a, b, x[ 7], S33); /* 47 */
|
||||
b = HH (b, c, d, a, x[15], S34); /* 48 */
|
||||
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
}
|
||||
|
||||
}
|
||||
235
jdkSrc/jdk8/sun/security/provider/MD5.java
Normal file
235
jdkSrc/jdk8/sun/security/provider/MD5.java
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static sun.security.provider.ByteArrayAccess.*;
|
||||
|
||||
/**
|
||||
* The MD5 class is used to compute an MD5 message digest over a given
|
||||
* buffer of bytes. It is an implementation of the RSA Data Security Inc
|
||||
* MD5 algorithim as described in internet RFC 1321.
|
||||
*
|
||||
* @author Chuck McManis
|
||||
* @author Benjamin Renaud
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public final class MD5 extends DigestBase {
|
||||
|
||||
// state of this object
|
||||
private int[] state;
|
||||
// temporary buffer, used by implCompress()
|
||||
private int[] x;
|
||||
|
||||
// rotation constants
|
||||
private static final int S11 = 7;
|
||||
private static final int S12 = 12;
|
||||
private static final int S13 = 17;
|
||||
private static final int S14 = 22;
|
||||
private static final int S21 = 5;
|
||||
private static final int S22 = 9;
|
||||
private static final int S23 = 14;
|
||||
private static final int S24 = 20;
|
||||
private static final int S31 = 4;
|
||||
private static final int S32 = 11;
|
||||
private static final int S33 = 16;
|
||||
private static final int S34 = 23;
|
||||
private static final int S41 = 6;
|
||||
private static final int S42 = 10;
|
||||
private static final int S43 = 15;
|
||||
private static final int S44 = 21;
|
||||
|
||||
// Standard constructor, creates a new MD5 instance.
|
||||
public MD5() {
|
||||
super("MD5", 16, 64);
|
||||
state = new int[4];
|
||||
x = new int[16];
|
||||
resetHashes();
|
||||
}
|
||||
|
||||
// clone this object
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
MD5 copy = (MD5) super.clone();
|
||||
copy.state = copy.state.clone();
|
||||
copy.x = new int[16];
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the state of this object.
|
||||
*/
|
||||
void implReset() {
|
||||
// Load magic initialization constants.
|
||||
resetHashes();
|
||||
// clear out old data
|
||||
Arrays.fill(x, 0);
|
||||
}
|
||||
|
||||
private void resetHashes() {
|
||||
state[0] = 0x67452301;
|
||||
state[1] = 0xefcdab89;
|
||||
state[2] = 0x98badcfe;
|
||||
state[3] = 0x10325476;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the final computations, any buffered bytes are added
|
||||
* to the digest, the count is added to the digest, and the resulting
|
||||
* digest is stored.
|
||||
*/
|
||||
void implDigest(byte[] out, int ofs) {
|
||||
long bitsProcessed = bytesProcessed << 3;
|
||||
|
||||
int index = (int)bytesProcessed & 0x3f;
|
||||
int padLen = (index < 56) ? (56 - index) : (120 - index);
|
||||
engineUpdate(padding, 0, padLen);
|
||||
|
||||
i2bLittle4((int)bitsProcessed, buffer, 56);
|
||||
i2bLittle4((int)(bitsProcessed >>> 32), buffer, 60);
|
||||
implCompress(buffer, 0);
|
||||
|
||||
i2bLittle(state, 0, out, ofs, 16);
|
||||
}
|
||||
|
||||
/* **********************************************************
|
||||
* The MD5 Functions. The results of this
|
||||
* implementation were checked against the RSADSI version.
|
||||
* **********************************************************
|
||||
*/
|
||||
|
||||
private static int FF(int a, int b, int c, int d, int x, int s, int ac) {
|
||||
a += ((b & c) | ((~b) & d)) + x + ac;
|
||||
return ((a << s) | (a >>> (32 - s))) + b;
|
||||
}
|
||||
|
||||
private static int GG(int a, int b, int c, int d, int x, int s, int ac) {
|
||||
a += ((b & d) | (c & (~d))) + x + ac;
|
||||
return ((a << s) | (a >>> (32 - s))) + b;
|
||||
}
|
||||
|
||||
private static int HH(int a, int b, int c, int d, int x, int s, int ac) {
|
||||
a += ((b ^ c) ^ d) + x + ac;
|
||||
return ((a << s) | (a >>> (32 - s))) + b;
|
||||
}
|
||||
|
||||
private static int II(int a, int b, int c, int d, int x, int s, int ac) {
|
||||
a += (c ^ (b | (~d))) + x + ac;
|
||||
return ((a << s) | (a >>> (32 - s))) + b;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is where the functions come together as the generic MD5
|
||||
* transformation operation. It consumes sixteen
|
||||
* bytes from the buffer, beginning at the specified offset.
|
||||
*/
|
||||
void implCompress(byte[] buf, int ofs) {
|
||||
b2iLittle64(buf, ofs, x);
|
||||
|
||||
int a = state[0];
|
||||
int b = state[1];
|
||||
int c = state[2];
|
||||
int d = state[3];
|
||||
|
||||
/* Round 1 */
|
||||
a = FF ( a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
|
||||
d = FF ( d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
|
||||
c = FF ( c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
|
||||
b = FF ( b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
|
||||
a = FF ( a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
|
||||
d = FF ( d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
|
||||
c = FF ( c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
|
||||
b = FF ( b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
|
||||
a = FF ( a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
|
||||
d = FF ( d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
|
||||
c = FF ( c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
|
||||
b = FF ( b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
|
||||
a = FF ( a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
|
||||
d = FF ( d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
|
||||
c = FF ( c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
|
||||
b = FF ( b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
|
||||
|
||||
/* Round 2 */
|
||||
a = GG ( a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
|
||||
d = GG ( d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
|
||||
c = GG ( c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
|
||||
b = GG ( b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
|
||||
a = GG ( a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
|
||||
d = GG ( d, a, b, c, x[10], S22, 0x2441453); /* 22 */
|
||||
c = GG ( c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
|
||||
b = GG ( b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
|
||||
a = GG ( a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
|
||||
d = GG ( d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
|
||||
c = GG ( c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
|
||||
b = GG ( b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
|
||||
a = GG ( a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
|
||||
d = GG ( d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
|
||||
c = GG ( c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
|
||||
b = GG ( b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
|
||||
|
||||
/* Round 3 */
|
||||
a = HH ( a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
|
||||
d = HH ( d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
|
||||
c = HH ( c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
|
||||
b = HH ( b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
|
||||
a = HH ( a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
|
||||
d = HH ( d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
|
||||
c = HH ( c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
|
||||
b = HH ( b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
|
||||
a = HH ( a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
|
||||
d = HH ( d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
|
||||
c = HH ( c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
|
||||
b = HH ( b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
|
||||
a = HH ( a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
|
||||
d = HH ( d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
|
||||
c = HH ( c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
|
||||
b = HH ( b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
|
||||
|
||||
/* Round 4 */
|
||||
a = II ( a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
|
||||
d = II ( d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
|
||||
c = II ( c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
|
||||
b = II ( b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
|
||||
a = II ( a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
|
||||
d = II ( d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
|
||||
c = II ( c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
|
||||
b = II ( b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
|
||||
a = II ( a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
|
||||
d = II ( d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
|
||||
c = II ( c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
|
||||
b = II ( b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
|
||||
a = II ( a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
|
||||
d = II ( d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
|
||||
c = II ( c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
|
||||
b = II ( b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
|
||||
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
}
|
||||
|
||||
}
|
||||
53
jdkSrc/jdk8/sun/security/provider/NativePRNG.java
Normal file
53
jdkSrc/jdk8/sun/security/provider/NativePRNG.java
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
/**
|
||||
* Native PRNG implementation for Windows. Currently a dummy, we do
|
||||
* not support a fully native PRNG on Windows.
|
||||
*
|
||||
* @since 1.5
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public final class NativePRNG {
|
||||
|
||||
// return whether the NativePRNG is available
|
||||
static boolean isAvailable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static final class NonBlocking {
|
||||
static boolean isAvailable() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Blocking {
|
||||
static boolean isAvailable() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
67
jdkSrc/jdk8/sun/security/provider/NativeSeedGenerator.java
Normal file
67
jdkSrc/jdk8/sun/security/provider/NativeSeedGenerator.java
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Seed generator for Windows making use of MS CryptoAPI using native code.
|
||||
*
|
||||
*/
|
||||
class NativeSeedGenerator extends SeedGenerator {
|
||||
|
||||
/**
|
||||
* Create a new CryptoAPI seed generator instances.
|
||||
*
|
||||
* @exception IOException if CryptoAPI seeds are not available
|
||||
* on this platform.
|
||||
*/
|
||||
NativeSeedGenerator(String seedFile) throws IOException {
|
||||
// seedFile is ignored.
|
||||
super();
|
||||
// try generating two random bytes to see if CAPI is available
|
||||
if (!nativeGenerateSeed(new byte[2])) {
|
||||
throw new IOException("Required native CryptoAPI features not "
|
||||
+ " available on this machine");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Native method to do the actual work.
|
||||
*/
|
||||
private static native boolean nativeGenerateSeed(byte[] result);
|
||||
|
||||
@Override
|
||||
void getSeedBytes(byte[] result) {
|
||||
// fill array as a side effect
|
||||
if (nativeGenerateSeed(result) == false) {
|
||||
// should never happen if constructor check succeeds
|
||||
throw new InternalError
|
||||
("Unexpected CryptoAPI failure generating seed");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
606
jdkSrc/jdk8/sun/security/provider/ParameterCache.java
Normal file
606
jdkSrc/jdk8/sun/security/provider/ParameterCache.java
Normal file
@@ -0,0 +1,606 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.spec.*;
|
||||
|
||||
import javax.crypto.spec.DHParameterSpec;
|
||||
import sun.security.util.SafeDHParameterSpec;
|
||||
|
||||
/**
|
||||
* Cache for DSA and DH parameter specs. Used by the KeyPairGenerators
|
||||
* in the Sun, SunJCE, and SunPKCS11 provider if no parameters have been
|
||||
* explicitly specified by the application.
|
||||
*
|
||||
* @author Andreas Sterbenz
|
||||
* @since 1.5
|
||||
*/
|
||||
public final class ParameterCache {
|
||||
|
||||
private ParameterCache() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// cache of DSA parameters
|
||||
private final static Map<Integer,DSAParameterSpec> dsaCache;
|
||||
|
||||
// cache of DH parameters
|
||||
private final static Map<Integer,DHParameterSpec> dhCache;
|
||||
|
||||
// convert DHParameterSpec to SafeDHParameterSpec if its parameters are
|
||||
// safe primes; validation takes time but should be worthwhile for the
|
||||
// parameter cache since the parameters may be reused many times.
|
||||
private static DHParameterSpec makeSafe(DHParameterSpec spec) {
|
||||
if (spec instanceof SafeDHParameterSpec) {
|
||||
return spec;
|
||||
}
|
||||
|
||||
BigInteger p = spec.getP();
|
||||
BigInteger g = spec.getG();
|
||||
|
||||
boolean isSafe = (g.equals(BigInteger.valueOf(2)) && p.testBit(0) &&
|
||||
p.shiftRight(1).isProbablePrime(100));
|
||||
if (isSafe) {
|
||||
return new SafeDHParameterSpec(p, g, spec.getL());
|
||||
} else {
|
||||
return spec;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return cached DSA parameters for the given length combination of
|
||||
* prime and subprime, or null if none are available in the cache.
|
||||
*/
|
||||
public static DSAParameterSpec getCachedDSAParameterSpec(int primeLen,
|
||||
int subprimeLen) {
|
||||
// ensure the sum is unique in all cases, i.e.
|
||||
// case#1: (512 <= p <= 1024) AND q=160
|
||||
// case#2: p=2048 AND q=224
|
||||
// case#3: p=2048 AND q=256
|
||||
// case#4: p=3072 AND q=256
|
||||
return dsaCache.get(Integer.valueOf(primeLen+subprimeLen));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return cached DH parameters for the given keylength, or null if none
|
||||
* are available in the cache.
|
||||
*/
|
||||
public static DHParameterSpec getCachedDHParameterSpec(int keyLength) {
|
||||
return dhCache.get(keyLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return DSA parameters for the given primeLen. Uses cache if
|
||||
* possible, generates new parameters and adds them to the cache
|
||||
* otherwise.
|
||||
*/
|
||||
public static DSAParameterSpec getDSAParameterSpec(int primeLen,
|
||||
SecureRandom random)
|
||||
throws NoSuchAlgorithmException, InvalidParameterSpecException,
|
||||
InvalidAlgorithmParameterException {
|
||||
if (primeLen <= 1024) {
|
||||
return getDSAParameterSpec(primeLen, 160, random);
|
||||
} else if (primeLen == 2048) {
|
||||
return getDSAParameterSpec(primeLen, 224, random);
|
||||
} else if (primeLen == 3072) {
|
||||
return getDSAParameterSpec(primeLen, 256, random);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return DSA parameters for the given primeLen and subprimeLen.
|
||||
* Uses cache if possible, generates new parameters and adds them to the
|
||||
* cache otherwise.
|
||||
*/
|
||||
public static DSAParameterSpec getDSAParameterSpec(int primeLen,
|
||||
int subprimeLen, SecureRandom random)
|
||||
throws NoSuchAlgorithmException, InvalidParameterSpecException,
|
||||
InvalidAlgorithmParameterException {
|
||||
DSAParameterSpec spec =
|
||||
getCachedDSAParameterSpec(primeLen, subprimeLen);
|
||||
if (spec != null) {
|
||||
return spec;
|
||||
}
|
||||
spec = getNewDSAParameterSpec(primeLen, subprimeLen, random);
|
||||
dsaCache.put(Integer.valueOf(primeLen + subprimeLen), spec);
|
||||
return spec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return DH parameters for the given keylength. Uses cache if possible,
|
||||
* generates new parameters and adds them to the cache otherwise.
|
||||
*/
|
||||
public static DHParameterSpec getDHParameterSpec(int keyLength,
|
||||
SecureRandom random)
|
||||
throws NoSuchAlgorithmException, InvalidParameterSpecException {
|
||||
DHParameterSpec spec = getCachedDHParameterSpec(keyLength);
|
||||
if (spec != null) {
|
||||
return spec;
|
||||
}
|
||||
AlgorithmParameterGenerator gen =
|
||||
AlgorithmParameterGenerator.getInstance("DH");
|
||||
gen.init(keyLength, random);
|
||||
AlgorithmParameters params = gen.generateParameters();
|
||||
spec = params.getParameterSpec(DHParameterSpec.class);
|
||||
dhCache.put(keyLength, makeSafe(spec));
|
||||
return spec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return new DSA parameters for the given length combination of prime and
|
||||
* sub prime. Do not lookup in cache and do not cache the newly generated
|
||||
* parameters. This method really only exists for the legacy method
|
||||
* DSAKeyPairGenerator.initialize(int, boolean, SecureRandom).
|
||||
*/
|
||||
public static DSAParameterSpec getNewDSAParameterSpec(int primeLen,
|
||||
int subprimeLen, SecureRandom random)
|
||||
throws NoSuchAlgorithmException, InvalidParameterSpecException,
|
||||
InvalidAlgorithmParameterException {
|
||||
AlgorithmParameterGenerator gen =
|
||||
AlgorithmParameterGenerator.getInstance("DSA");
|
||||
// Use init(int size, SecureRandom random) for legacy DSA key sizes
|
||||
if (primeLen < 1024) {
|
||||
gen.init(primeLen, random);
|
||||
} else {
|
||||
DSAGenParameterSpec genParams =
|
||||
new DSAGenParameterSpec(primeLen, subprimeLen);
|
||||
gen.init(genParams, random);
|
||||
}
|
||||
AlgorithmParameters params = gen.generateParameters();
|
||||
DSAParameterSpec spec = params.getParameterSpec(DSAParameterSpec.class);
|
||||
return spec;
|
||||
}
|
||||
|
||||
static {
|
||||
dhCache = new ConcurrentHashMap<Integer,DHParameterSpec>();
|
||||
dsaCache = new ConcurrentHashMap<Integer,DSAParameterSpec>();
|
||||
|
||||
/*
|
||||
* We support precomputed parameter for legacy 512, 768 bit moduli,
|
||||
* and (L, N) combinations of (1024, 160), (2048, 224), (2048, 256),
|
||||
* (3072, 256). In this file we provide both the seed and counter
|
||||
* value of the generation process for each of these seeds,
|
||||
* for validation purposes. We also include the test vectors
|
||||
* from the DSA specification, FIPS 186, and the FIPS 186
|
||||
* Change No 1, which updates the test vector using SHA-1
|
||||
* instead of SHA (for both the G function and the message
|
||||
* hash.
|
||||
*/
|
||||
|
||||
/*
|
||||
* L = 512
|
||||
* SEED = b869c82b35d70e1b1ff91b28e37a62ecdc34409b
|
||||
* counter = 123
|
||||
*/
|
||||
BigInteger p512 =
|
||||
new BigInteger("fca682ce8e12caba26efccf7110e526db078b05edecb" +
|
||||
"cd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e1" +
|
||||
"2ed0899bcd132acd50d99151bdc43ee737592e17", 16);
|
||||
|
||||
BigInteger q512 =
|
||||
new BigInteger("962eddcc369cba8ebb260ee6b6a126d9346e38c5", 16);
|
||||
|
||||
BigInteger g512 =
|
||||
new BigInteger("678471b27a9cf44ee91a49c5147db1a9aaf244f05a43" +
|
||||
"4d6486931d2d14271b9e35030b71fd73da179069b32e" +
|
||||
"2935630e1c2062354d0da20a6c416e50be794ca4", 16);
|
||||
|
||||
/*
|
||||
* L = 768
|
||||
* SEED = 77d0f8c4dad15eb8c4f2f8d6726cefd96d5bb399
|
||||
* counter = 263
|
||||
*/
|
||||
BigInteger p768 =
|
||||
new BigInteger("e9e642599d355f37c97ffd3567120b8e25c9cd43e" +
|
||||
"927b3a9670fbec5d890141922d2c3b3ad24800937" +
|
||||
"99869d1e846aab49fab0ad26d2ce6a22219d470bc" +
|
||||
"e7d777d4a21fbe9c270b57f607002f3cef8393694" +
|
||||
"cf45ee3688c11a8c56ab127a3daf", 16);
|
||||
|
||||
BigInteger q768 =
|
||||
new BigInteger("9cdbd84c9f1ac2f38d0f80f42ab952e7338bf511",
|
||||
16);
|
||||
|
||||
BigInteger g768 =
|
||||
new BigInteger("30470ad5a005fb14ce2d9dcd87e38bc7d1b1c5fac" +
|
||||
"baecbe95f190aa7a31d23c4dbbcbe06174544401a" +
|
||||
"5b2c020965d8c2bd2171d3668445771f74ba084d2" +
|
||||
"029d83c1c158547f3a9f1a2715be23d51ae4d3e5a" +
|
||||
"1f6a7064f316933a346d3f529252", 16);
|
||||
|
||||
|
||||
/*
|
||||
* L = 1024
|
||||
* SEED = 8d5155894229d5e689ee01e6018a237e2cae64cd
|
||||
* counter = 92
|
||||
*/
|
||||
BigInteger p1024 =
|
||||
new BigInteger("fd7f53811d75122952df4a9c2eece4e7f611b7523c" +
|
||||
"ef4400c31e3f80b6512669455d402251fb593d8d58" +
|
||||
"fabfc5f5ba30f6cb9b556cd7813b801d346ff26660" +
|
||||
"b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c6" +
|
||||
"1bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554" +
|
||||
"135a169132f675f3ae2b61d72aeff22203199dd148" +
|
||||
"01c7", 16);
|
||||
|
||||
BigInteger q1024 =
|
||||
new BigInteger("9760508f15230bccb292b982a2eb840bf0581cf5",
|
||||
16);
|
||||
|
||||
BigInteger g1024 =
|
||||
new BigInteger("f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa" +
|
||||
"3aea82f9574c0b3d0782675159578ebad4594fe671" +
|
||||
"07108180b449167123e84c281613b7cf09328cc8a6" +
|
||||
"e13c167a8b547c8d28e0a3ae1e2bb3a675916ea37f" +
|
||||
"0bfa213562f1fb627a01243bcca4f1bea8519089a8" +
|
||||
"83dfe15ae59f06928b665e807b552564014c3bfecf" +
|
||||
"492a", 16);
|
||||
|
||||
dsaCache.put(Integer.valueOf(512+160),
|
||||
new DSAParameterSpec(p512, q512, g512));
|
||||
dsaCache.put(Integer.valueOf(768+160),
|
||||
new DSAParameterSpec(p768, q768, g768));
|
||||
dsaCache.put(Integer.valueOf(1024+160),
|
||||
new DSAParameterSpec(p1024, q1024, g1024));
|
||||
/*
|
||||
* L = 2048, N = 224
|
||||
* SEED = 584236080cfa43c09b02354135f4cc5198a19efada08bd866d601ba4
|
||||
* counter = 2666
|
||||
*/
|
||||
BigInteger p2048_224 =
|
||||
new BigInteger("8f7935d9b9aae9bfabed887acf4951b6f32ec59e3b" +
|
||||
"af3718e8eac4961f3efd3606e74351a9c4183339b8" +
|
||||
"09e7c2ae1c539ba7475b85d011adb8b47987754984" +
|
||||
"695cac0e8f14b3360828a22ffa27110a3d62a99345" +
|
||||
"3409a0fe696c4658f84bdd20819c3709a01057b195" +
|
||||
"adcd00233dba5484b6291f9d648ef883448677979c" +
|
||||
"ec04b434a6ac2e75e9985de23db0292fc1118c9ffa" +
|
||||
"9d8181e7338db792b730d7b9e349592f6809987215" +
|
||||
"3915ea3d6b8b4653c633458f803b32a4c2e0f27290" +
|
||||
"256e4e3f8a3b0838a1c450e4e18c1a29a37ddf5ea1" +
|
||||
"43de4b66ff04903ed5cf1623e158d487c608e97f21" +
|
||||
"1cd81dca23cb6e380765f822e342be484c05763939" +
|
||||
"601cd667", 16);
|
||||
|
||||
BigInteger q2048_224 =
|
||||
new BigInteger("baf696a68578f7dfdee7fa67c977c785ef32b233ba" +
|
||||
"e580c0bcd5695d", 16);
|
||||
|
||||
BigInteger g2048_224 =
|
||||
new BigInteger("16a65c58204850704e7502a39757040d34da3a3478" +
|
||||
"c154d4e4a5c02d242ee04f96e61e4bd0904abdac8f" +
|
||||
"37eeb1e09f3182d23c9043cb642f88004160edf9ca" +
|
||||
"09b32076a79c32a627f2473e91879ba2c4e744bd20" +
|
||||
"81544cb55b802c368d1fa83ed489e94e0fa0688e32" +
|
||||
"428a5c78c478c68d0527b71c9a3abb0b0be12c4468" +
|
||||
"9639e7d3ce74db101a65aa2b87f64c6826db3ec72f" +
|
||||
"4b5599834bb4edb02f7c90e9a496d3a55d535bebfc" +
|
||||
"45d4f619f63f3dedbb873925c2f224e07731296da8" +
|
||||
"87ec1e4748f87efb5fdeb75484316b2232dee553dd" +
|
||||
"af02112b0d1f02da30973224fe27aeda8b9d4b2922" +
|
||||
"d9ba8be39ed9e103a63c52810bc688b7e2ed4316e1" +
|
||||
"ef17dbde", 16);
|
||||
|
||||
dsaCache.put(Integer.valueOf(2048+224),
|
||||
new DSAParameterSpec(p2048_224, q2048_224, g2048_224));
|
||||
|
||||
/*
|
||||
* L = 2048, N = 256
|
||||
* SEED = b0b4417601b59cbc9d8ac8f935cadaec \
|
||||
* 4f5fbb2f23785609ae466748d9b5a536
|
||||
* counter = 497
|
||||
*/
|
||||
BigInteger p2048_256 =
|
||||
new BigInteger("95475cf5d93e596c3fcd1d902add02f427f5f3c721" +
|
||||
"0313bb45fb4d5bb2e5fe1cbd678cd4bbdd84c9836b" +
|
||||
"e1f31c0777725aeb6c2fc38b85f48076fa76bcd814" +
|
||||
"6cc89a6fb2f706dd719898c2083dc8d896f84062e2" +
|
||||
"c9c94d137b054a8d8096adb8d51952398eeca852a0" +
|
||||
"af12df83e475aa65d4ec0c38a9560d5661186ff98b" +
|
||||
"9fc9eb60eee8b030376b236bc73be3acdbd74fd61c" +
|
||||
"1d2475fa3077b8f080467881ff7e1ca56fee066d79" +
|
||||
"506ade51edbb5443a563927dbc4ba520086746175c" +
|
||||
"8885925ebc64c6147906773496990cb714ec667304" +
|
||||
"e261faee33b3cbdf008e0c3fa90650d97d3909c927" +
|
||||
"5bf4ac86ffcb3d03e6dfc8ada5934242dd6d3bcca2" +
|
||||
"a406cb0b", 16);
|
||||
|
||||
BigInteger q2048_256 =
|
||||
new BigInteger("f8183668ba5fc5bb06b5981e6d8b795d30b8978d43" +
|
||||
"ca0ec572e37e09939a9773", 16);
|
||||
|
||||
BigInteger g2048_256 =
|
||||
new BigInteger("42debb9da5b3d88cc956e08787ec3f3a09bba5f48b" +
|
||||
"889a74aaf53174aa0fbe7e3c5b8fcd7a53bef563b0" +
|
||||
"e98560328960a9517f4014d3325fc7962bf1e04937" +
|
||||
"0d76d1314a76137e792f3f0db859d095e4a5b93202" +
|
||||
"4f079ecf2ef09c797452b0770e1350782ed57ddf79" +
|
||||
"4979dcef23cb96f183061965c4ebc93c9c71c56b92" +
|
||||
"5955a75f94cccf1449ac43d586d0beee43251b0b22" +
|
||||
"87349d68de0d144403f13e802f4146d882e057af19" +
|
||||
"b6f6275c6676c8fa0e3ca2713a3257fd1b27d0639f" +
|
||||
"695e347d8d1cf9ac819a26ca9b04cb0eb9b7b03598" +
|
||||
"8d15bbac65212a55239cfc7e58fae38d7250ab9991" +
|
||||
"ffbc97134025fe8ce04c4399ad96569be91a546f49" +
|
||||
"78693c7a", 16);
|
||||
|
||||
dsaCache.put(Integer.valueOf(2048+256),
|
||||
new DSAParameterSpec(p2048_256, q2048_256, g2048_256));
|
||||
|
||||
|
||||
/*
|
||||
* L = 3072, N = 256
|
||||
* SEED = 9fe304be4d6b9919559f39d5911d12e9 \
|
||||
* 5158d6946598cd59775b8f3b8fff3a3f
|
||||
* counter = 1186
|
||||
*/
|
||||
BigInteger p3072_256 = new BigInteger(
|
||||
"ea9cda9f5fbda66dd830494609405687ab7cf38538e058d1" +
|
||||
"e2f68dea95364866e1c05beacded24227edee28cad80bcec" +
|
||||
"ad39913be3b713267b3b96c8d9f0f6a03b5dfc9222d5cfe4" +
|
||||
"afcc9982f33784f760c3b759aebe3bbe9098a6b84c96f1fd" +
|
||||
"e44ce11c084c2a082c7a76a0ef142928b4f328406ab9beb2" +
|
||||
"4f84577dd0f46ce86fd8f08488269998bf4742d6425f7a0e" +
|
||||
"c75d8660c5dd6f4e3b3d3bee81b2c21afe8c9e8b84b87192" +
|
||||
"e2cc20f961d2bcd8133afcf3675ab80681cb374c78f33e29" +
|
||||
"d1011083d89f9c5728b94676fccb1b57bc60288c15d85ae8" +
|
||||
"38ae1941c5a20ae2b2049b3583fe30da455ddb3e6ad9b995" +
|
||||
"5cd9bb5681431622beb0f92da533fcab496cebc447aa1bb5" +
|
||||
"a8039522f2da98ff416289323a64df626ab6881870927dce" +
|
||||
"e387f13b5c9d24d6cba1d82ed375a082506ee87bc7ae3006" +
|
||||
"7f4a94e2ee363d992c40f2725b5db4b3525ebde22bbbfd0f" +
|
||||
"a124a588b0f5a4acb3a86951aff09f8c8198fb5b53da0c93" +
|
||||
"1cedc598b4f835b779d04d99026c7ba08c4b27f118ac1e3d", 16);
|
||||
|
||||
BigInteger q3072_256 = new BigInteger(
|
||||
"c4eeac2bbab79bd831946d717a56a6e687547aa8e9c5494a" +
|
||||
"5a4b2f4ca13d6c11", 16);
|
||||
|
||||
BigInteger g3072_256 = new BigInteger(
|
||||
"42e5fa7844f8fa9d8998d830d004e7b15b1d276bcbe5f12c" +
|
||||
"35ec90c1a25f5832018a6724bd9cdbe803b675509bed167f" +
|
||||
"3d7cf8599fc865c6d5a0f79158c1bc918f00a944d0ad0f38" +
|
||||
"f520fb91d85d82674d0d5f874faa5fcdfe56cd178c1afdc7" +
|
||||
"ce8795727b7dee966ed0b3c5cedcef8aca628befebf2d105" +
|
||||
"c7aff8eb0da9c9610737dd64dce1237b82c1b2bc8608d55f" +
|
||||
"fda98d7189444e65883315669c05716bde36c78b130aa3df" +
|
||||
"2e4d609914c7c8dc470f4e300187c775f81e7b1a9c0dce40" +
|
||||
"5d6eab2cbb9d9c4ef44412ba573dd403c4ed7bc2364772f5" +
|
||||
"6a30c48de78f5003f9371c55262d2c8ac2246ade3b02fdcf" +
|
||||
"cf5cbfde74fbcbfe6e0e0fdf3160764f84d311c179a40af6" +
|
||||
"79a8f47ab13c8f706893245eb11edcce451fa2ab98001998" +
|
||||
"7f125d8dc96622d419ba0d71f16c6024dce9d364c3b26d8e" +
|
||||
"c1a3c828f6c9d14b1d0333b95db77bfdbe3c6bce5337a1a5" +
|
||||
"a7ace10111219448447197e2a344cc423be768bb89e27be6" +
|
||||
"cbd22085614a5a3360be23b1bfbb6e6e6471363d32c85d31", 16);
|
||||
|
||||
dsaCache.put(Integer.valueOf(3072+256),
|
||||
new DSAParameterSpec(p3072_256, q3072_256, g3072_256));
|
||||
|
||||
//
|
||||
// Diffie-Hellman Groups
|
||||
//
|
||||
|
||||
// the common generator
|
||||
BigInteger dhG = BigInteger.valueOf(2);
|
||||
|
||||
// Self generated following the approach from RFC 2412 Appendix E but
|
||||
// using random source instead of binary expansion of pi
|
||||
BigInteger dhP512 = new BigInteger(
|
||||
"FFFFFFFFFFFFFFFF8B479B3A6E8DE86C294188F0BF2CD86C" +
|
||||
"DB950ADB36D0F61FD51E46F69C99ED95ABE5A7BBB230A6ED" +
|
||||
"1D0B4506B5317284FFFFFFFFFFFFFFFF", 16);
|
||||
//
|
||||
// From RFC 7296
|
||||
|
||||
// The prime is: 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 }
|
||||
BigInteger dhP768 = new BigInteger(
|
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
|
||||
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
|
||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
|
||||
"E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF", 16);
|
||||
|
||||
// The prime is 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }
|
||||
BigInteger dhP1024 = new BigInteger(
|
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
|
||||
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
|
||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
|
||||
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
|
||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" +
|
||||
"FFFFFFFFFFFFFFFF", 16);
|
||||
|
||||
//
|
||||
// From RFC 3526
|
||||
|
||||
// The prime is: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }
|
||||
BigInteger dhP1536 = new BigInteger(
|
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
|
||||
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
|
||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
|
||||
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
|
||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
|
||||
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
|
||||
"83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
|
||||
"670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 16);
|
||||
|
||||
// This prime is: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }
|
||||
BigInteger dhP2048 = new BigInteger(
|
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
|
||||
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
|
||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
|
||||
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
|
||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
|
||||
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
|
||||
"83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
|
||||
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
|
||||
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
|
||||
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
|
||||
"15728E5A8AACAA68FFFFFFFFFFFFFFFF", 16);
|
||||
|
||||
// This prime is: 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 }
|
||||
BigInteger dhP3072 = new BigInteger(
|
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
|
||||
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
|
||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
|
||||
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
|
||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
|
||||
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
|
||||
"83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
|
||||
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
|
||||
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
|
||||
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
|
||||
"15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" +
|
||||
"ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" +
|
||||
"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" +
|
||||
"F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" +
|
||||
"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" +
|
||||
"43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF", 16);
|
||||
|
||||
// This prime is: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 }
|
||||
BigInteger dhP4096 = new BigInteger(
|
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
|
||||
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
|
||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
|
||||
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
|
||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
|
||||
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
|
||||
"83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
|
||||
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
|
||||
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
|
||||
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
|
||||
"15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" +
|
||||
"ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" +
|
||||
"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" +
|
||||
"F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" +
|
||||
"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" +
|
||||
"43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" +
|
||||
"88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" +
|
||||
"2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" +
|
||||
"287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" +
|
||||
"1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" +
|
||||
"93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" +
|
||||
"FFFFFFFFFFFFFFFF", 16);
|
||||
|
||||
// This prime is: 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 }
|
||||
BigInteger dhP6144 = new BigInteger(
|
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" +
|
||||
"8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" +
|
||||
"302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" +
|
||||
"A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" +
|
||||
"49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" +
|
||||
"FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
|
||||
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" +
|
||||
"180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" +
|
||||
"3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" +
|
||||
"04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" +
|
||||
"B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" +
|
||||
"1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" +
|
||||
"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" +
|
||||
"E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" +
|
||||
"99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" +
|
||||
"04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" +
|
||||
"233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" +
|
||||
"D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" +
|
||||
"36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406" +
|
||||
"AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918" +
|
||||
"DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151" +
|
||||
"2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03" +
|
||||
"F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F" +
|
||||
"BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" +
|
||||
"CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B" +
|
||||
"B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632" +
|
||||
"387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E" +
|
||||
"6DCC4024FFFFFFFFFFFFFFFF", 16);
|
||||
|
||||
// This prime is: 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 }
|
||||
BigInteger dhP8192 = new BigInteger(
|
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
|
||||
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
|
||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
|
||||
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
|
||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
|
||||
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
|
||||
"83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
|
||||
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
|
||||
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
|
||||
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
|
||||
"15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" +
|
||||
"ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" +
|
||||
"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" +
|
||||
"F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" +
|
||||
"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" +
|
||||
"43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" +
|
||||
"88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" +
|
||||
"2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" +
|
||||
"287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" +
|
||||
"1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" +
|
||||
"93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" +
|
||||
"36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" +
|
||||
"F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" +
|
||||
"179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" +
|
||||
"DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" +
|
||||
"5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" +
|
||||
"D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" +
|
||||
"23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" +
|
||||
"CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" +
|
||||
"06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" +
|
||||
"DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" +
|
||||
"12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" +
|
||||
"38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300" +
|
||||
"741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" +
|
||||
"3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" +
|
||||
"22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" +
|
||||
"4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A" +
|
||||
"062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" +
|
||||
"4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1" +
|
||||
"B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" +
|
||||
"4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47" +
|
||||
"9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" +
|
||||
"60C980DD98EDD3DFFFFFFFFFFFFFFFFF", 16);
|
||||
|
||||
// self-generated safe prime
|
||||
dhCache.put(512, new SafeDHParameterSpec(dhP512, dhG));
|
||||
|
||||
// from RFC 7296
|
||||
dhCache.put(768, new SafeDHParameterSpec(dhP768, dhG));
|
||||
dhCache.put(1024, new SafeDHParameterSpec(dhP1024, dhG));
|
||||
// from RFC 3526
|
||||
dhCache.put(1536, new SafeDHParameterSpec(dhP1536, dhG));
|
||||
dhCache.put(2048, new SafeDHParameterSpec(dhP2048, dhG));
|
||||
dhCache.put(3072, new SafeDHParameterSpec(dhP3072, dhG));
|
||||
dhCache.put(4096, new SafeDHParameterSpec(dhP4096, dhG));
|
||||
dhCache.put(6144, new SafeDHParameterSpec(dhP6144, dhG));
|
||||
dhCache.put(8192, new SafeDHParameterSpec(dhP8192, dhG));
|
||||
}
|
||||
}
|
||||
2372
jdkSrc/jdk8/sun/security/provider/PolicyFile.java
Normal file
2372
jdkSrc/jdk8/sun/security/provider/PolicyFile.java
Normal file
File diff suppressed because it is too large
Load Diff
1435
jdkSrc/jdk8/sun/security/provider/PolicyParser.java
Normal file
1435
jdkSrc/jdk8/sun/security/provider/PolicyParser.java
Normal file
File diff suppressed because it is too large
Load Diff
81
jdkSrc/jdk8/sun/security/provider/PolicySpiFile.java
Normal file
81
jdkSrc/jdk8/sun/security/provider/PolicySpiFile.java
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.security.CodeSource;
|
||||
import java.security.Permission;
|
||||
import java.security.PermissionCollection;
|
||||
import java.security.Policy;
|
||||
import java.security.PolicySpi;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.security.URIParameter;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
/**
|
||||
* This class wraps the PolicyFile subclass implementation of Policy
|
||||
* inside a PolicySpi implementation that is available from the SUN provider
|
||||
* via the Policy.getInstance calls.
|
||||
*
|
||||
*/
|
||||
public final class PolicySpiFile extends PolicySpi {
|
||||
|
||||
private PolicyFile pf;
|
||||
|
||||
public PolicySpiFile(Policy.Parameters params) {
|
||||
|
||||
if (params == null) {
|
||||
pf = new PolicyFile();
|
||||
} else {
|
||||
if (!(params instanceof URIParameter)) {
|
||||
throw new IllegalArgumentException
|
||||
("Unrecognized policy parameter: " + params);
|
||||
}
|
||||
URIParameter uriParam = (URIParameter)params;
|
||||
try {
|
||||
pf = new PolicyFile(uriParam.getURI().toURL());
|
||||
} catch (MalformedURLException mue) {
|
||||
throw new IllegalArgumentException("Invalid URIParameter", mue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected PermissionCollection engineGetPermissions(CodeSource codesource) {
|
||||
return pf.getPermissions(codesource);
|
||||
}
|
||||
|
||||
protected PermissionCollection engineGetPermissions(ProtectionDomain d) {
|
||||
return pf.getPermissions(d);
|
||||
}
|
||||
|
||||
protected boolean engineImplies(ProtectionDomain d, Permission p) {
|
||||
return pf.implies(d, p);
|
||||
}
|
||||
|
||||
protected void engineRefresh() {
|
||||
pf.refresh();
|
||||
}
|
||||
}
|
||||
211
jdkSrc/jdk8/sun/security/provider/SHA.java
Normal file
211
jdkSrc/jdk8/sun/security/provider/SHA.java
Normal file
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static sun.security.provider.ByteArrayAccess.*;
|
||||
|
||||
/**
|
||||
* This class implements the Secure Hash Algorithm (SHA) developed by
|
||||
* the National Institute of Standards and Technology along with the
|
||||
* National Security Agency. This is the updated version of SHA
|
||||
* fip-180 as superseded by fip-180-1.
|
||||
*
|
||||
* <p>It implement JavaSecurity MessageDigest, and can be used by in
|
||||
* the Java Security framework, as a pluggable implementation, as a
|
||||
* filter for the digest stream classes.
|
||||
*
|
||||
* @author Roger Riggs
|
||||
* @author Benjamin Renaud
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public final class SHA extends DigestBase {
|
||||
|
||||
// Buffer of int's and count of characters accumulated
|
||||
// 64 bytes are included in each hash block so the low order
|
||||
// bits of count are used to know how to pack the bytes into ints
|
||||
// and to know when to compute the block and start the next one.
|
||||
private int[] W;
|
||||
|
||||
// state of this
|
||||
private int[] state;
|
||||
|
||||
/**
|
||||
* Creates a new SHA object.
|
||||
*/
|
||||
public SHA() {
|
||||
super("SHA-1", 20, 64);
|
||||
state = new int[5];
|
||||
W = new int[80];
|
||||
resetHashes();
|
||||
}
|
||||
|
||||
/*
|
||||
* Clones this object.
|
||||
*/
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
SHA copy = (SHA) super.clone();
|
||||
copy.state = copy.state.clone();
|
||||
copy.W = new int[80];
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the buffers and hash value to start a new hash.
|
||||
*/
|
||||
void implReset() {
|
||||
// Load magic initialization constants.
|
||||
resetHashes();
|
||||
// clear out old data
|
||||
Arrays.fill(W, 0);
|
||||
}
|
||||
|
||||
private void resetHashes() {
|
||||
state[0] = 0x67452301;
|
||||
state[1] = 0xefcdab89;
|
||||
state[2] = 0x98badcfe;
|
||||
state[3] = 0x10325476;
|
||||
state[4] = 0xc3d2e1f0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the final hash and copies the 20 bytes to the output array.
|
||||
*/
|
||||
void implDigest(byte[] out, int ofs) {
|
||||
long bitsProcessed = bytesProcessed << 3;
|
||||
|
||||
int index = (int)bytesProcessed & 0x3f;
|
||||
int padLen = (index < 56) ? (56 - index) : (120 - index);
|
||||
engineUpdate(padding, 0, padLen);
|
||||
|
||||
i2bBig4((int)(bitsProcessed >>> 32), buffer, 56);
|
||||
i2bBig4((int)bitsProcessed, buffer, 60);
|
||||
implCompress(buffer, 0);
|
||||
|
||||
i2bBig(state, 0, out, ofs, 20);
|
||||
}
|
||||
|
||||
// Constants for each round
|
||||
private final static int round1_kt = 0x5a827999;
|
||||
private final static int round2_kt = 0x6ed9eba1;
|
||||
private final static int round3_kt = 0x8f1bbcdc;
|
||||
private final static int round4_kt = 0xca62c1d6;
|
||||
|
||||
/**
|
||||
* Compute a the hash for the current block.
|
||||
*
|
||||
* This is in the same vein as Peter Gutmann's algorithm listed in
|
||||
* the back of Applied Cryptography, Compact implementation of
|
||||
* "old" NIST Secure Hash Algorithm.
|
||||
*/
|
||||
void implCompress(byte[] buf, int ofs) {
|
||||
implCompressCheck(buf, ofs);
|
||||
implCompress0(buf, ofs);
|
||||
}
|
||||
|
||||
private void implCompressCheck(byte[] buf, int ofs) {
|
||||
Objects.requireNonNull(buf);
|
||||
|
||||
// The checks performed by the method 'b2iBig64'
|
||||
// are sufficient for the case when the method
|
||||
// 'implCompressImpl' is replaced with a compiler
|
||||
// intrinsic.
|
||||
b2iBig64(buf, ofs, W);
|
||||
}
|
||||
|
||||
// The method 'implCompressImpl seems not to use its parameters.
|
||||
// The method can, however, be replaced with a compiler intrinsic
|
||||
// that operates directly on the array 'buf' (starting from
|
||||
// offset 'ofs') and not on array 'W', therefore 'buf' and 'ofs'
|
||||
// must be passed as parameter to the method.
|
||||
private void implCompress0(byte[] buf, int ofs) {
|
||||
// The first 16 ints have the byte stream, compute the rest of
|
||||
// the buffer
|
||||
for (int t = 16; t <= 79; t++) {
|
||||
int temp = W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16];
|
||||
W[t] = (temp << 1) | (temp >>> 31);
|
||||
}
|
||||
|
||||
int a = state[0];
|
||||
int b = state[1];
|
||||
int c = state[2];
|
||||
int d = state[3];
|
||||
int e = state[4];
|
||||
|
||||
// Round 1
|
||||
for (int i = 0; i < 20; i++) {
|
||||
int temp = ((a<<5) | (a>>>(32-5))) +
|
||||
((b&c)|((~b)&d))+ e + W[i] + round1_kt;
|
||||
e = d;
|
||||
d = c;
|
||||
c = ((b<<30) | (b>>>(32-30)));
|
||||
b = a;
|
||||
a = temp;
|
||||
}
|
||||
|
||||
// Round 2
|
||||
for (int i = 20; i < 40; i++) {
|
||||
int temp = ((a<<5) | (a>>>(32-5))) +
|
||||
(b ^ c ^ d) + e + W[i] + round2_kt;
|
||||
e = d;
|
||||
d = c;
|
||||
c = ((b<<30) | (b>>>(32-30)));
|
||||
b = a;
|
||||
a = temp;
|
||||
}
|
||||
|
||||
// Round 3
|
||||
for (int i = 40; i < 60; i++) {
|
||||
int temp = ((a<<5) | (a>>>(32-5))) +
|
||||
((b&c)|(b&d)|(c&d)) + e + W[i] + round3_kt;
|
||||
e = d;
|
||||
d = c;
|
||||
c = ((b<<30) | (b>>>(32-30)));
|
||||
b = a;
|
||||
a = temp;
|
||||
}
|
||||
|
||||
// Round 4
|
||||
for (int i = 60; i < 80; i++) {
|
||||
int temp = ((a<<5) | (a>>>(32-5))) +
|
||||
(b ^ c ^ d) + e + W[i] + round4_kt;
|
||||
e = d;
|
||||
d = c;
|
||||
c = ((b<<30) | (b>>>(32-30)));
|
||||
b = a;
|
||||
a = temp;
|
||||
}
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
}
|
||||
|
||||
}
|
||||
290
jdkSrc/jdk8/sun/security/provider/SHA2.java
Normal file
290
jdkSrc/jdk8/sun/security/provider/SHA2.java
Normal file
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static sun.security.provider.ByteArrayAccess.*;
|
||||
|
||||
/**
|
||||
* This class implements the Secure Hash Algorithm SHA-256 developed by
|
||||
* the National Institute of Standards and Technology along with the
|
||||
* National Security Agency.
|
||||
*
|
||||
* <p>It implements java.security.MessageDigestSpi, and can be used
|
||||
* through Java Cryptography Architecture (JCA), as a pluggable
|
||||
* MessageDigest implementation.
|
||||
*
|
||||
* @since 1.4.2
|
||||
* @author Valerie Peng
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
abstract class SHA2 extends DigestBase {
|
||||
|
||||
private static final int ITERATION = 64;
|
||||
// Constants for each round
|
||||
private static final int[] ROUND_CONSTS = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
|
||||
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
||||
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
|
||||
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
|
||||
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
|
||||
// buffer used by implCompress()
|
||||
private int[] W;
|
||||
|
||||
// state of this object
|
||||
private int[] state;
|
||||
|
||||
// initial state value. different between SHA-224 and SHA-256
|
||||
private final int[] initialHashes;
|
||||
|
||||
/**
|
||||
* Creates a new SHA object.
|
||||
*/
|
||||
SHA2(String name, int digestLength, int[] initialHashes) {
|
||||
super(name, digestLength, 64);
|
||||
this.initialHashes = initialHashes;
|
||||
state = new int[8];
|
||||
W = new int[64];
|
||||
resetHashes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the buffers and hash value to start a new hash.
|
||||
*/
|
||||
void implReset() {
|
||||
resetHashes();
|
||||
Arrays.fill(W, 0);
|
||||
}
|
||||
|
||||
private void resetHashes() {
|
||||
System.arraycopy(initialHashes, 0, state, 0, state.length);
|
||||
}
|
||||
|
||||
void implDigest(byte[] out, int ofs) {
|
||||
long bitsProcessed = bytesProcessed << 3;
|
||||
|
||||
int index = (int)bytesProcessed & 0x3f;
|
||||
int padLen = (index < 56) ? (56 - index) : (120 - index);
|
||||
engineUpdate(padding, 0, padLen);
|
||||
|
||||
i2bBig4((int)(bitsProcessed >>> 32), buffer, 56);
|
||||
i2bBig4((int)bitsProcessed, buffer, 60);
|
||||
implCompress(buffer, 0);
|
||||
|
||||
i2bBig(state, 0, out, ofs, engineGetDigestLength());
|
||||
}
|
||||
|
||||
/**
|
||||
* logical function ch(x,y,z) as defined in spec:
|
||||
* @return (x and y) xor ((complement x) and z)
|
||||
* @param x int
|
||||
* @param y int
|
||||
* @param z int
|
||||
*/
|
||||
private static int lf_ch(int x, int y, int z) {
|
||||
return (x & y) ^ ((~x) & z);
|
||||
}
|
||||
|
||||
/**
|
||||
* logical function maj(x,y,z) as defined in spec:
|
||||
* @return (x and y) xor (x and z) xor (y and z)
|
||||
* @param x int
|
||||
* @param y int
|
||||
* @param z int
|
||||
*/
|
||||
private static int lf_maj(int x, int y, int z) {
|
||||
return (x & y) ^ (x & z) ^ (y & z);
|
||||
}
|
||||
|
||||
/**
|
||||
* logical function R(x,s) - right shift
|
||||
* @return x right shift for s times
|
||||
* @param x int
|
||||
* @param s int
|
||||
*/
|
||||
private static int lf_R( int x, int s ) {
|
||||
return (x >>> s);
|
||||
}
|
||||
|
||||
/**
|
||||
* logical function S(x,s) - right rotation
|
||||
* @return x circular right shift for s times
|
||||
* @param x int
|
||||
* @param s int
|
||||
*/
|
||||
private static int lf_S(int x, int s) {
|
||||
return (x >>> s) | (x << (32 - s));
|
||||
}
|
||||
|
||||
/**
|
||||
* logical function sigma0(x) - xor of results of right rotations
|
||||
* @return S(x,2) xor S(x,13) xor S(x,22)
|
||||
* @param x int
|
||||
*/
|
||||
private static int lf_sigma0(int x) {
|
||||
return lf_S(x, 2) ^ lf_S(x, 13) ^ lf_S(x, 22);
|
||||
}
|
||||
|
||||
/**
|
||||
* logical function sigma1(x) - xor of results of right rotations
|
||||
* @return S(x,6) xor S(x,11) xor S(x,25)
|
||||
* @param x int
|
||||
*/
|
||||
private static int lf_sigma1(int x) {
|
||||
return lf_S( x, 6 ) ^ lf_S( x, 11 ) ^ lf_S( x, 25 );
|
||||
}
|
||||
|
||||
/**
|
||||
* logical function delta0(x) - xor of results of right shifts/rotations
|
||||
* @return int
|
||||
* @param x int
|
||||
*/
|
||||
private static int lf_delta0(int x) {
|
||||
return lf_S(x, 7) ^ lf_S(x, 18) ^ lf_R(x, 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* logical function delta1(x) - xor of results of right shifts/rotations
|
||||
* @return int
|
||||
* @param x int
|
||||
*/
|
||||
private static int lf_delta1(int x) {
|
||||
return lf_S(x, 17) ^ lf_S(x, 19) ^ lf_R(x, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the current block to update the state variable state.
|
||||
*/
|
||||
void implCompress(byte[] buf, int ofs) {
|
||||
implCompressCheck(buf, ofs);
|
||||
implCompress0(buf, ofs);
|
||||
}
|
||||
|
||||
private void implCompressCheck(byte[] buf, int ofs) {
|
||||
Objects.requireNonNull(buf);
|
||||
|
||||
// The checks performed by the method 'b2iBig64'
|
||||
// are sufficient for the case when the method
|
||||
// 'implCompressImpl' is replaced with a compiler
|
||||
// intrinsic.
|
||||
b2iBig64(buf, ofs, W);
|
||||
}
|
||||
|
||||
// The method 'implCompressImpl' seems not to use its parameters.
|
||||
// The method can, however, be replaced with a compiler intrinsic
|
||||
// that operates directly on the array 'buf' (starting from
|
||||
// offset 'ofs') and not on array 'W', therefore 'buf' and 'ofs'
|
||||
// must be passed as parameter to the method.
|
||||
private void implCompress0(byte[] buf, int ofs) {
|
||||
// The first 16 ints are from the byte stream, compute the rest of
|
||||
// the W[]'s
|
||||
for (int t = 16; t < ITERATION; t++) {
|
||||
W[t] = lf_delta1(W[t-2]) + W[t-7] + lf_delta0(W[t-15])
|
||||
+ W[t-16];
|
||||
}
|
||||
|
||||
int a = state[0];
|
||||
int b = state[1];
|
||||
int c = state[2];
|
||||
int d = state[3];
|
||||
int e = state[4];
|
||||
int f = state[5];
|
||||
int g = state[6];
|
||||
int h = state[7];
|
||||
|
||||
for (int i = 0; i < ITERATION; i++) {
|
||||
int T1 = h + lf_sigma1(e) + lf_ch(e,f,g) + ROUND_CONSTS[i] + W[i];
|
||||
int T2 = lf_sigma0(a) + lf_maj(a,b,c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + T1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = T1 + T2;
|
||||
}
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
state[5] += f;
|
||||
state[6] += g;
|
||||
state[7] += h;
|
||||
}
|
||||
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
SHA2 copy = (SHA2) super.clone();
|
||||
copy.state = copy.state.clone();
|
||||
copy.W = new int[64];
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* SHA-224 implementation class.
|
||||
*/
|
||||
public static final class SHA224 extends SHA2 {
|
||||
private static final int[] INITIAL_HASHES = {
|
||||
0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
|
||||
0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4
|
||||
};
|
||||
|
||||
public SHA224() {
|
||||
super("SHA-224", 28, INITIAL_HASHES);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SHA-256 implementation class.
|
||||
*/
|
||||
public static final class SHA256 extends SHA2 {
|
||||
private static final int[] INITIAL_HASHES = {
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
||||
};
|
||||
|
||||
public SHA256() {
|
||||
super("SHA-256", 32, INITIAL_HASHES);
|
||||
}
|
||||
}
|
||||
}
|
||||
345
jdkSrc/jdk8/sun/security/provider/SHA5.java
Normal file
345
jdkSrc/jdk8/sun/security/provider/SHA5.java
Normal file
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
import static sun.security.provider.ByteArrayAccess.*;
|
||||
|
||||
/**
|
||||
* This class implements the Secure Hash Algorithm SHA-384 and SHA-512
|
||||
* developed by the National Institute of Standards and Technology along
|
||||
* with the National Security Agency.
|
||||
*
|
||||
* The two algorithms are almost identical. This file contains a base
|
||||
* class SHA5 and two nested static subclasses as the classes to be used
|
||||
* by the JCA framework.
|
||||
*
|
||||
* <p>It implements java.security.MessageDigestSpi, and can be used
|
||||
* through Java Cryptography Architecture (JCA), as a pluggable
|
||||
* MessageDigest implementation.
|
||||
*
|
||||
* @since 1.4.2
|
||||
* @author Valerie Peng
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
abstract class SHA5 extends DigestBase {
|
||||
|
||||
private static final int ITERATION = 80;
|
||||
// Constants for each round/iteration
|
||||
private static final long[] ROUND_CONSTS = {
|
||||
0x428A2F98D728AE22L, 0x7137449123EF65CDL, 0xB5C0FBCFEC4D3B2FL,
|
||||
0xE9B5DBA58189DBBCL, 0x3956C25BF348B538L, 0x59F111F1B605D019L,
|
||||
0x923F82A4AF194F9BL, 0xAB1C5ED5DA6D8118L, 0xD807AA98A3030242L,
|
||||
0x12835B0145706FBEL, 0x243185BE4EE4B28CL, 0x550C7DC3D5FFB4E2L,
|
||||
0x72BE5D74F27B896FL, 0x80DEB1FE3B1696B1L, 0x9BDC06A725C71235L,
|
||||
0xC19BF174CF692694L, 0xE49B69C19EF14AD2L, 0xEFBE4786384F25E3L,
|
||||
0x0FC19DC68B8CD5B5L, 0x240CA1CC77AC9C65L, 0x2DE92C6F592B0275L,
|
||||
0x4A7484AA6EA6E483L, 0x5CB0A9DCBD41FBD4L, 0x76F988DA831153B5L,
|
||||
0x983E5152EE66DFABL, 0xA831C66D2DB43210L, 0xB00327C898FB213FL,
|
||||
0xBF597FC7BEEF0EE4L, 0xC6E00BF33DA88FC2L, 0xD5A79147930AA725L,
|
||||
0x06CA6351E003826FL, 0x142929670A0E6E70L, 0x27B70A8546D22FFCL,
|
||||
0x2E1B21385C26C926L, 0x4D2C6DFC5AC42AEDL, 0x53380D139D95B3DFL,
|
||||
0x650A73548BAF63DEL, 0x766A0ABB3C77B2A8L, 0x81C2C92E47EDAEE6L,
|
||||
0x92722C851482353BL, 0xA2BFE8A14CF10364L, 0xA81A664BBC423001L,
|
||||
0xC24B8B70D0F89791L, 0xC76C51A30654BE30L, 0xD192E819D6EF5218L,
|
||||
0xD69906245565A910L, 0xF40E35855771202AL, 0x106AA07032BBD1B8L,
|
||||
0x19A4C116B8D2D0C8L, 0x1E376C085141AB53L, 0x2748774CDF8EEB99L,
|
||||
0x34B0BCB5E19B48A8L, 0x391C0CB3C5C95A63L, 0x4ED8AA4AE3418ACBL,
|
||||
0x5B9CCA4F7763E373L, 0x682E6FF3D6B2B8A3L, 0x748F82EE5DEFB2FCL,
|
||||
0x78A5636F43172F60L, 0x84C87814A1F0AB72L, 0x8CC702081A6439ECL,
|
||||
0x90BEFFFA23631E28L, 0xA4506CEBDE82BDE9L, 0xBEF9A3F7B2C67915L,
|
||||
0xC67178F2E372532BL, 0xCA273ECEEA26619CL, 0xD186B8C721C0C207L,
|
||||
0xEADA7DD6CDE0EB1EL, 0xF57D4F7FEE6ED178L, 0x06F067AA72176FBAL,
|
||||
0x0A637DC5A2C898A6L, 0x113F9804BEF90DAEL, 0x1B710B35131C471BL,
|
||||
0x28DB77F523047D84L, 0x32CAAB7B40C72493L, 0x3C9EBE0A15C9BEBCL,
|
||||
0x431D67C49C100D4CL, 0x4CC5D4BECB3E42B6L, 0x597F299CFC657E2AL,
|
||||
0x5FCB6FAB3AD6FAECL, 0x6C44198C4A475817L
|
||||
};
|
||||
|
||||
// buffer used by implCompress()
|
||||
private long[] W;
|
||||
|
||||
// state of this object
|
||||
private long[] state;
|
||||
|
||||
// initial state value. different between SHA-384 and SHA-512
|
||||
private final long[] initialHashes;
|
||||
|
||||
/**
|
||||
* Creates a new SHA object.
|
||||
*/
|
||||
SHA5(String name, int digestLength, long[] initialHashes) {
|
||||
super(name, digestLength, 128);
|
||||
this.initialHashes = initialHashes;
|
||||
state = new long[8];
|
||||
W = new long[80];
|
||||
resetHashes();
|
||||
}
|
||||
|
||||
final void implReset() {
|
||||
resetHashes();
|
||||
Arrays.fill(W, 0L);
|
||||
}
|
||||
|
||||
private void resetHashes() {
|
||||
System.arraycopy(initialHashes, 0, state, 0, state.length);
|
||||
}
|
||||
|
||||
final void implDigest(byte[] out, int ofs) {
|
||||
long bitsProcessed = bytesProcessed << 3;
|
||||
|
||||
int index = (int)bytesProcessed & 0x7f;
|
||||
int padLen = (index < 112) ? (112 - index) : (240 - index);
|
||||
engineUpdate(padding, 0, padLen + 8);
|
||||
|
||||
i2bBig4((int)(bitsProcessed >>> 32), buffer, 120);
|
||||
i2bBig4((int)bitsProcessed, buffer, 124);
|
||||
implCompress(buffer, 0);
|
||||
|
||||
int len = engineGetDigestLength();
|
||||
if (len == 28) {
|
||||
// Special case for SHA-512/224
|
||||
l2bBig(state, 0, out, ofs, 24);
|
||||
i2bBig4((int)(state[3] >> 32), out, ofs + 24);
|
||||
} else {
|
||||
l2bBig(state, 0, out, ofs, len);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* logical function ch(x,y,z) as defined in spec:
|
||||
* @return (x and y) xor ((complement x) and z)
|
||||
* @param x long
|
||||
* @param y long
|
||||
* @param z long
|
||||
*/
|
||||
private static long lf_ch(long x, long y, long z) {
|
||||
return (x & y) ^ ((~x) & z);
|
||||
}
|
||||
|
||||
/**
|
||||
* logical function maj(x,y,z) as defined in spec:
|
||||
* @return (x and y) xor (x and z) xor (y and z)
|
||||
* @param x long
|
||||
* @param y long
|
||||
* @param z long
|
||||
*/
|
||||
private static long lf_maj(long x, long y, long z) {
|
||||
return (x & y) ^ (x & z) ^ (y & z);
|
||||
}
|
||||
|
||||
/**
|
||||
* logical function R(x,s) - right shift
|
||||
* @return x right shift for s times
|
||||
* @param x long
|
||||
* @param s int
|
||||
*/
|
||||
private static long lf_R(long x, int s) {
|
||||
return (x >>> s);
|
||||
}
|
||||
|
||||
/**
|
||||
* logical function S(x,s) - right rotation
|
||||
* @return x circular right shift for s times
|
||||
* @param x long
|
||||
* @param s int
|
||||
*/
|
||||
private static long lf_S(long x, int s) {
|
||||
return (x >>> s) | (x << (64 - s));
|
||||
}
|
||||
|
||||
/**
|
||||
* logical function sigma0(x) - xor of results of right rotations
|
||||
* @return S(x,28) xor S(x,34) xor S(x,39)
|
||||
* @param x long
|
||||
*/
|
||||
private static long lf_sigma0(long x) {
|
||||
return lf_S(x, 28) ^ lf_S(x, 34) ^ lf_S(x, 39);
|
||||
}
|
||||
|
||||
/**
|
||||
* logical function sigma1(x) - xor of results of right rotations
|
||||
* @return S(x,14) xor S(x,18) xor S(x,41)
|
||||
* @param x long
|
||||
*/
|
||||
private static long lf_sigma1(long x) {
|
||||
return lf_S(x, 14) ^ lf_S(x, 18) ^ lf_S(x, 41);
|
||||
}
|
||||
|
||||
/**
|
||||
* logical function delta0(x) - xor of results of right shifts/rotations
|
||||
* @return long
|
||||
* @param x long
|
||||
*/
|
||||
private static long lf_delta0(long x) {
|
||||
return lf_S(x, 1) ^ lf_S(x, 8) ^ lf_R(x, 7);
|
||||
}
|
||||
|
||||
/**
|
||||
* logical function delta1(x) - xor of results of right shifts/rotations
|
||||
* @return long
|
||||
* @param x long
|
||||
*/
|
||||
private static long lf_delta1(long x) {
|
||||
return lf_S(x, 19) ^ lf_S(x, 61) ^ lf_R(x, 6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the hash for the current block.
|
||||
*
|
||||
* This is in the same vein as Peter Gutmann's algorithm listed in
|
||||
* the back of Applied Cryptography, Compact implementation of
|
||||
* "old" NIST Secure Hash Algorithm.
|
||||
*/
|
||||
final void implCompress(byte[] buf, int ofs) {
|
||||
implCompressCheck(buf, ofs);
|
||||
implCompress0(buf, ofs);
|
||||
}
|
||||
|
||||
private void implCompressCheck(byte[] buf, int ofs) {
|
||||
Objects.requireNonNull(buf);
|
||||
|
||||
// The checks performed by the method 'b2iBig128'
|
||||
// are sufficient for the case when the method
|
||||
// 'implCompressImpl' is replaced with a compiler
|
||||
// intrinsic.
|
||||
b2lBig128(buf, ofs, W);
|
||||
}
|
||||
|
||||
// The method 'implCompressImpl' seems not to use its parameters.
|
||||
// The method can, however, be replaced with a compiler intrinsic
|
||||
// that operates directly on the array 'buf' (starting from
|
||||
// offset 'ofs') and not on array 'W', therefore 'buf' and 'ofs'
|
||||
// must be passed as parameter to the method.
|
||||
private final void implCompress0(byte[] buf, int ofs) {
|
||||
// The first 16 longs are from the byte stream, compute the rest of
|
||||
// the W[]'s
|
||||
for (int t = 16; t < ITERATION; t++) {
|
||||
W[t] = lf_delta1(W[t-2]) + W[t-7] + lf_delta0(W[t-15])
|
||||
+ W[t-16];
|
||||
}
|
||||
|
||||
long a = state[0];
|
||||
long b = state[1];
|
||||
long c = state[2];
|
||||
long d = state[3];
|
||||
long e = state[4];
|
||||
long f = state[5];
|
||||
long g = state[6];
|
||||
long h = state[7];
|
||||
|
||||
for (int i = 0; i < ITERATION; i++) {
|
||||
long T1 = h + lf_sigma1(e) + lf_ch(e,f,g) + ROUND_CONSTS[i] + W[i];
|
||||
long T2 = lf_sigma0(a) + lf_maj(a,b,c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + T1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = T1 + T2;
|
||||
}
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
state[5] += f;
|
||||
state[6] += g;
|
||||
state[7] += h;
|
||||
}
|
||||
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
SHA5 copy = (SHA5) super.clone();
|
||||
copy.state = copy.state.clone();
|
||||
copy.W = new long[80];
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* SHA-512 implementation class.
|
||||
*/
|
||||
public static final class SHA512 extends SHA5 {
|
||||
|
||||
private static final long[] INITIAL_HASHES = {
|
||||
0x6a09e667f3bcc908L, 0xbb67ae8584caa73bL,
|
||||
0x3c6ef372fe94f82bL, 0xa54ff53a5f1d36f1L,
|
||||
0x510e527fade682d1L, 0x9b05688c2b3e6c1fL,
|
||||
0x1f83d9abfb41bd6bL, 0x5be0cd19137e2179L
|
||||
};
|
||||
|
||||
public SHA512() {
|
||||
super("SHA-512", 64, INITIAL_HASHES);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SHA-384 implementation class.
|
||||
*/
|
||||
public static final class SHA384 extends SHA5 {
|
||||
|
||||
private static final long[] INITIAL_HASHES = {
|
||||
0xcbbb9d5dc1059ed8L, 0x629a292a367cd507L,
|
||||
0x9159015a3070dd17L, 0x152fecd8f70e5939L,
|
||||
0x67332667ffc00b31L, 0x8eb44a8768581511L,
|
||||
0xdb0c2e0d64f98fa7L, 0x47b5481dbefa4fa4L
|
||||
};
|
||||
|
||||
public SHA384() {
|
||||
super("SHA-384", 48, INITIAL_HASHES);
|
||||
}
|
||||
}
|
||||
public static final class SHA512_224 extends SHA5 {
|
||||
|
||||
private static final long[] INITIAL_HASHES = {
|
||||
0x8C3D37C819544DA2L, 0x73E1996689DCD4D6L,
|
||||
0x1DFAB7AE32FF9C82L, 0x679DD514582F9FCFL,
|
||||
0x0F6D2B697BD44DA8L, 0x77E36F7304C48942L,
|
||||
0x3F9D85A86A1D36C8L, 0x1112E6AD91D692A1L
|
||||
};
|
||||
|
||||
public SHA512_224() {
|
||||
super("SHA-512/224", 28, INITIAL_HASHES);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class SHA512_256 extends SHA5 {
|
||||
|
||||
private static final long[] INITIAL_HASHES = {
|
||||
0x22312194FC2BF72CL, 0x9F555FA3C84C64C2L,
|
||||
0x2393B86B6F53B151L, 0x963877195940EABDL,
|
||||
0x96283EE2A88EFFE3L, 0xBE5E1E2553863992L,
|
||||
0x2B0199FC2C85B8AAL, 0x0EB72DDC81C52CA2L
|
||||
};
|
||||
|
||||
public SHA512_256() {
|
||||
super("SHA-512/256", 32, INITIAL_HASHES);
|
||||
}
|
||||
}
|
||||
}
|
||||
330
jdkSrc/jdk8/sun/security/provider/SecureRandom.java
Normal file
330
jdkSrc/jdk8/sun/security/provider/SecureRandom.java
Normal file
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.SecureRandomSpi;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
|
||||
/**
|
||||
* <p>This class provides a crytpographically strong pseudo-random number
|
||||
* generator based on the SHA-1 hash algorithm.
|
||||
*
|
||||
* <p>Note that if a seed is not provided, we attempt to provide sufficient
|
||||
* seed bytes to completely randomize the internal state of the generator
|
||||
* (20 bytes). However, our seed generation algorithm has not been thoroughly
|
||||
* studied or widely deployed.
|
||||
*
|
||||
* <p>Also note that when a random object is deserialized,
|
||||
* <a href="#engineNextBytes(byte[])">engineNextBytes</a> invoked on the
|
||||
* restored random object will yield the exact same (random) bytes as the
|
||||
* original object. If this behaviour is not desired, the restored random
|
||||
* object should be seeded, using
|
||||
* <a href="#engineSetSeed(byte[])">engineSetSeed</a>.
|
||||
*
|
||||
* @author Benjamin Renaud
|
||||
* @author Josh Bloch
|
||||
* @author Gadi Guy
|
||||
*/
|
||||
|
||||
public final class SecureRandom extends SecureRandomSpi
|
||||
implements java.io.Serializable {
|
||||
|
||||
private static final long serialVersionUID = 3581829991155417889L;
|
||||
|
||||
private static final int DIGEST_SIZE = 20;
|
||||
private transient MessageDigest digest;
|
||||
private byte[] state;
|
||||
private byte[] remainder;
|
||||
private int remCount;
|
||||
|
||||
/**
|
||||
* This empty constructor automatically seeds the generator. We attempt
|
||||
* to provide sufficient seed bytes to completely randomize the internal
|
||||
* state of the generator (20 bytes). Note, however, that our seed
|
||||
* generation algorithm has not been thoroughly studied or widely deployed.
|
||||
*
|
||||
* <p>The first time this constructor is called in a given Virtual Machine,
|
||||
* it may take several seconds of CPU time to seed the generator, depending
|
||||
* on the underlying hardware. Successive calls run quickly because they
|
||||
* rely on the same (internal) pseudo-random number generator for their
|
||||
* seed bits.
|
||||
*/
|
||||
public SecureRandom() {
|
||||
init(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructor is used to instantiate the private seeder object
|
||||
* with a given seed from the SeedGenerator.
|
||||
*
|
||||
* @param seed the seed.
|
||||
*/
|
||||
private SecureRandom(byte seed[]) {
|
||||
init(seed);
|
||||
}
|
||||
|
||||
/**
|
||||
* This call, used by the constructors, instantiates the SHA digest
|
||||
* and sets the seed, if given.
|
||||
*/
|
||||
private void init(byte[] seed) {
|
||||
try {
|
||||
/*
|
||||
* Use the local SUN implementation to avoid native
|
||||
* performance overhead.
|
||||
*/
|
||||
digest = MessageDigest.getInstance("SHA", "SUN");
|
||||
} catch (NoSuchProviderException | NoSuchAlgorithmException e) {
|
||||
// Fallback to any available.
|
||||
try {
|
||||
digest = MessageDigest.getInstance("SHA");
|
||||
} catch (NoSuchAlgorithmException exc) {
|
||||
throw new InternalError(
|
||||
"internal error: SHA-1 not available.", exc);
|
||||
}
|
||||
}
|
||||
|
||||
if (seed != null) {
|
||||
engineSetSeed(seed);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given number of seed bytes, computed using the seed
|
||||
* generation algorithm that this class uses to seed itself. This
|
||||
* call may be used to seed other random number generators. While
|
||||
* we attempt to return a "truly random" sequence of bytes, we do not
|
||||
* know exactly how random the bytes returned by this call are. (See
|
||||
* the empty constructor <a href = "#SecureRandom">SecureRandom</a>
|
||||
* for a brief description of the underlying algorithm.)
|
||||
* The prudent user will err on the side of caution and get extra
|
||||
* seed bytes, although it should be noted that seed generation is
|
||||
* somewhat costly.
|
||||
*
|
||||
* @param numBytes the number of seed bytes to generate.
|
||||
*
|
||||
* @return the seed bytes.
|
||||
*/
|
||||
@Override
|
||||
public byte[] engineGenerateSeed(int numBytes) {
|
||||
// Neither of the SeedGenerator implementations require
|
||||
// locking, so no sync needed here.
|
||||
byte[] b = new byte[numBytes];
|
||||
SeedGenerator.generateSeed(b);
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reseeds this random object. The given seed supplements, rather than
|
||||
* replaces, the existing seed. Thus, repeated calls are guaranteed
|
||||
* never to reduce randomness.
|
||||
*
|
||||
* @param seed the seed.
|
||||
*/
|
||||
@Override
|
||||
synchronized public void engineSetSeed(byte[] seed) {
|
||||
if (state != null) {
|
||||
digest.update(state);
|
||||
for (int i = 0; i < state.length; i++) {
|
||||
state[i] = 0;
|
||||
}
|
||||
}
|
||||
state = digest.digest(seed);
|
||||
}
|
||||
|
||||
private static void updateState(byte[] state, byte[] output) {
|
||||
int last = 1;
|
||||
int v;
|
||||
byte t;
|
||||
boolean zf = false;
|
||||
|
||||
// state(n + 1) = (state(n) + output(n) + 1) % 2^160;
|
||||
for (int i = 0; i < state.length; i++) {
|
||||
// Add two bytes
|
||||
v = (int)state[i] + (int)output[i] + last;
|
||||
// Result is lower 8 bits
|
||||
t = (byte)v;
|
||||
// Store result. Check for state collision.
|
||||
zf = zf | (state[i] != t);
|
||||
state[i] = t;
|
||||
// High 8 bits are carry. Store for next iteration.
|
||||
last = v >> 8;
|
||||
}
|
||||
|
||||
// Make sure at least one bit changes!
|
||||
if (!zf) {
|
||||
state[0]++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This static object will be seeded by SeedGenerator, and used
|
||||
* to seed future instances of SHA1PRNG SecureRandoms.
|
||||
* <p>
|
||||
* Bloch, Effective Java Second Edition: Item 71
|
||||
*/
|
||||
private static class SeederHolder {
|
||||
|
||||
private static final SecureRandom seeder;
|
||||
|
||||
static {
|
||||
/*
|
||||
* Call to SeedGenerator.generateSeed() to add additional
|
||||
* seed material (likely from the Native implementation).
|
||||
*/
|
||||
seeder = new SecureRandom(SeedGenerator.getSystemEntropy());
|
||||
byte [] b = new byte[DIGEST_SIZE];
|
||||
SeedGenerator.generateSeed(b);
|
||||
seeder.engineSetSeed(b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a user-specified number of random bytes.
|
||||
*
|
||||
* @param bytes the array to be filled in with random bytes.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void engineNextBytes(byte[] result) {
|
||||
int index = 0;
|
||||
int todo;
|
||||
byte[] output = remainder;
|
||||
|
||||
if (state == null) {
|
||||
byte[] seed = new byte[DIGEST_SIZE];
|
||||
SeederHolder.seeder.engineNextBytes(seed);
|
||||
state = digest.digest(seed);
|
||||
}
|
||||
|
||||
// Use remainder from last time
|
||||
int r = remCount;
|
||||
if (r > 0) {
|
||||
// How many bytes?
|
||||
todo = (result.length - index) < (DIGEST_SIZE - r) ?
|
||||
(result.length - index) : (DIGEST_SIZE - r);
|
||||
// Copy the bytes, zero the buffer
|
||||
for (int i = 0; i < todo; i++) {
|
||||
result[i] = output[r];
|
||||
output[r++] = 0;
|
||||
}
|
||||
remCount += todo;
|
||||
index += todo;
|
||||
}
|
||||
|
||||
// If we need more bytes, make them.
|
||||
while (index < result.length) {
|
||||
// Step the state
|
||||
digest.update(state);
|
||||
output = digest.digest();
|
||||
updateState(state, output);
|
||||
|
||||
// How many bytes?
|
||||
todo = (result.length - index) > DIGEST_SIZE ?
|
||||
DIGEST_SIZE : result.length - index;
|
||||
// Copy the bytes, zero the buffer
|
||||
for (int i = 0; i < todo; i++) {
|
||||
result[index++] = output[i];
|
||||
output[i] = 0;
|
||||
}
|
||||
remCount += todo;
|
||||
}
|
||||
|
||||
// Store remainder for next time
|
||||
remainder = output;
|
||||
remCount %= DIGEST_SIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is called to restore the state of the random object from
|
||||
* a stream.
|
||||
* <p>
|
||||
* We have to create a new instance of {@code MessageDigest}, because
|
||||
* it is not included in the stream (it is marked "transient").
|
||||
* <p>
|
||||
* Note that the {@code engineNextBytes()} method invoked on the restored
|
||||
* random object will yield the exact same (random) bytes as the original.
|
||||
* If you do not want this behaviour, you should re-seed the restored
|
||||
* random object, using {@code engineSetSeed()}.
|
||||
*
|
||||
* @param s the {@code ObjectInputStream} from which data is read
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws ClassNotFoundException if a serialized class cannot be loaded
|
||||
*/
|
||||
private void readObject(java.io.ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException {
|
||||
|
||||
s.defaultReadObject ();
|
||||
|
||||
try {
|
||||
/*
|
||||
* Use the local SUN implementation to avoid native
|
||||
* performance overhead.
|
||||
*/
|
||||
digest = MessageDigest.getInstance("SHA", "SUN");
|
||||
} catch (NoSuchProviderException | NoSuchAlgorithmException e) {
|
||||
// Fallback to any available.
|
||||
try {
|
||||
digest = MessageDigest.getInstance("SHA");
|
||||
} catch (NoSuchAlgorithmException exc) {
|
||||
throw new InternalError(
|
||||
"internal error: SHA-1 not available.", exc);
|
||||
}
|
||||
}
|
||||
|
||||
// Various consistency checks
|
||||
if ((remainder == null) && (remCount > 0)) {
|
||||
throw new InvalidObjectException(
|
||||
"Remainder indicated, but no data available");
|
||||
}
|
||||
|
||||
// Not yet allocated state
|
||||
if (state == null) {
|
||||
if (remainder == null) {
|
||||
return;
|
||||
} else {
|
||||
throw new InvalidObjectException(
|
||||
"Inconsistent buffer allocations");
|
||||
}
|
||||
}
|
||||
|
||||
// Sanity check on sizes/pointer
|
||||
if ((state.length != DIGEST_SIZE) ||
|
||||
((remainder != null) && (remainder.length != DIGEST_SIZE)) ||
|
||||
(remCount < 0 ) || (remCount >= DIGEST_SIZE)) {
|
||||
throw new InvalidObjectException(
|
||||
"Inconsistent buffer sizes/state");
|
||||
}
|
||||
|
||||
state = state.clone();
|
||||
if (remainder != null) {
|
||||
remainder = remainder.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
554
jdkSrc/jdk8/sun/security/provider/SeedGenerator.java
Normal file
554
jdkSrc/jdk8/sun/security/provider/SeedGenerator.java
Normal file
@@ -0,0 +1,554 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
/**
|
||||
* This class generates seeds for the SHA1PRNG cryptographically strong
|
||||
* random number generator.
|
||||
* <p>
|
||||
* The seed is produced using one of two techniques, via a computation
|
||||
* of current system activity or from an entropy gathering device.
|
||||
* <p>
|
||||
* In the default technique the seed is produced by counting the
|
||||
* number of times the VM manages to loop in a given period. This number
|
||||
* roughly reflects the machine load at that point in time.
|
||||
* The samples are translated using a permutation (s-box)
|
||||
* and then XORed together. This process is non linear and
|
||||
* should prevent the samples from "averaging out". The s-box
|
||||
* was designed to have even statistical distribution; it's specific
|
||||
* values are not crucial for the security of the seed.
|
||||
* We also create a number of sleeper threads which add entropy
|
||||
* to the system by keeping the scheduler busy.
|
||||
* Twenty such samples should give us roughly 160 bits of randomness.
|
||||
* <p>
|
||||
* These values are gathered in the background by a daemon thread
|
||||
* thus allowing the system to continue performing it's different
|
||||
* activites, which in turn add entropy to the random seed.
|
||||
* <p>
|
||||
* The class also gathers miscellaneous system information, some
|
||||
* machine dependent, some not. This information is then hashed together
|
||||
* with the 20 seed bytes.
|
||||
* <p>
|
||||
* The alternative to the above approach is to acquire seed material
|
||||
* from an entropy gathering device, such as /dev/random. This can be
|
||||
* accomplished by setting the value of the {@code securerandom.source}
|
||||
* Security property to a URL specifying the location of the entropy
|
||||
* gathering device, or by setting the {@code java.security.egd} System
|
||||
* property.
|
||||
* <p>
|
||||
* In the event the specified URL cannot be accessed the default
|
||||
* threading mechanism is used.
|
||||
*
|
||||
* @author Joshua Bloch
|
||||
* @author Gadi Guy
|
||||
*/
|
||||
|
||||
import java.security.*;
|
||||
import java.io.*;
|
||||
import java.util.Properties;
|
||||
import java.util.Enumeration;
|
||||
import java.net.*;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Random;
|
||||
import sun.security.util.Debug;
|
||||
|
||||
abstract class SeedGenerator {
|
||||
|
||||
// Static instance is created at link time
|
||||
private static SeedGenerator instance;
|
||||
|
||||
private static final Debug debug = Debug.getInstance("provider");
|
||||
|
||||
// Static initializer to hook in selected or best performing generator
|
||||
static {
|
||||
String egdSource = SunEntries.getSeedSource();
|
||||
|
||||
/*
|
||||
* Try the URL specifying the source (e.g. file:/dev/random)
|
||||
*
|
||||
* The URLs "file:/dev/random" or "file:/dev/urandom" are used to
|
||||
* indicate the SeedGenerator should use OS support, if available.
|
||||
*
|
||||
* On Windows, this causes the MS CryptoAPI seeder to be used.
|
||||
*
|
||||
* On Solaris/Linux/MacOS, this is identical to using
|
||||
* URLSeedGenerator to read from /dev/[u]random
|
||||
*/
|
||||
if (egdSource.equals(SunEntries.URL_DEV_RANDOM) ||
|
||||
egdSource.equals(SunEntries.URL_DEV_URANDOM)) {
|
||||
try {
|
||||
instance = new NativeSeedGenerator(egdSource);
|
||||
if (debug != null) {
|
||||
debug.println(
|
||||
"Using operating system seed generator" + egdSource);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (debug != null) {
|
||||
debug.println("Failed to use operating system seed "
|
||||
+ "generator: " + e.toString());
|
||||
}
|
||||
}
|
||||
} else if (egdSource.length() != 0) {
|
||||
try {
|
||||
instance = new URLSeedGenerator(egdSource);
|
||||
if (debug != null) {
|
||||
debug.println("Using URL seed generator reading from "
|
||||
+ egdSource);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (debug != null) {
|
||||
debug.println("Failed to create seed generator with "
|
||||
+ egdSource + ": " + e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to ThreadedSeedGenerator
|
||||
if (instance == null) {
|
||||
if (debug != null) {
|
||||
debug.println("Using default threaded seed generator");
|
||||
}
|
||||
instance = new ThreadedSeedGenerator();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill result with bytes from the queue. Wait for it if it isn't ready.
|
||||
*/
|
||||
static public void generateSeed(byte[] result) {
|
||||
instance.getSeedBytes(result);
|
||||
}
|
||||
|
||||
abstract void getSeedBytes(byte[] result);
|
||||
|
||||
/**
|
||||
* Retrieve some system information, hashed.
|
||||
*/
|
||||
static byte[] getSystemEntropy() {
|
||||
byte[] ba;
|
||||
final MessageDigest md;
|
||||
|
||||
try {
|
||||
md = MessageDigest.getInstance("SHA");
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
throw new InternalError("internal error: SHA-1 not available."
|
||||
, nsae);
|
||||
}
|
||||
|
||||
// The current time in millis
|
||||
byte b =(byte)System.currentTimeMillis();
|
||||
md.update(b);
|
||||
|
||||
java.security.AccessController.doPrivileged
|
||||
(new java.security.PrivilegedAction<Void>() {
|
||||
@Override
|
||||
public Void run() {
|
||||
try {
|
||||
// System properties can change from machine to machine
|
||||
String s;
|
||||
Properties p = System.getProperties();
|
||||
Enumeration<?> e = p.propertyNames();
|
||||
while (e.hasMoreElements()) {
|
||||
s =(String)e.nextElement();
|
||||
md.update(s.getBytes());
|
||||
md.update(p.getProperty(s).getBytes());
|
||||
}
|
||||
|
||||
// Include network adapter names (and a Mac address)
|
||||
addNetworkAdapterInfo(md);
|
||||
|
||||
// The temporary dir
|
||||
File f = new File(p.getProperty("java.io.tmpdir"));
|
||||
int count = 0;
|
||||
try (
|
||||
DirectoryStream<Path> stream =
|
||||
Files.newDirectoryStream(f.toPath())) {
|
||||
// We use a Random object to choose what file names
|
||||
// should be used. Otherwise on a machine with too
|
||||
// many files, the same first 1024 files always get
|
||||
// used. Any, We make sure the first 512 files are
|
||||
// always used.
|
||||
Random r = new Random();
|
||||
for (Path entry: stream) {
|
||||
if (count < 512 || r.nextBoolean()) {
|
||||
md.update(entry.getFileName()
|
||||
.toString().getBytes());
|
||||
}
|
||||
if (count++ > 1024) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
md.update((byte)ex.hashCode());
|
||||
}
|
||||
|
||||
// get Runtime memory stats
|
||||
Runtime rt = Runtime.getRuntime();
|
||||
byte[] memBytes = longToByteArray(rt.totalMemory());
|
||||
md.update(memBytes, 0, memBytes.length);
|
||||
memBytes = longToByteArray(rt.freeMemory());
|
||||
md.update(memBytes, 0, memBytes.length);
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
return md.digest();
|
||||
}
|
||||
|
||||
/*
|
||||
* Include network adapter names and, if available, a Mac address
|
||||
*
|
||||
* See also java.util.concurrent.ThreadLocalRandom.initialSeed()
|
||||
*/
|
||||
private static void addNetworkAdapterInfo(MessageDigest md) {
|
||||
|
||||
try {
|
||||
Enumeration<NetworkInterface> ifcs =
|
||||
NetworkInterface.getNetworkInterfaces();
|
||||
while (ifcs.hasMoreElements()) {
|
||||
NetworkInterface ifc = ifcs.nextElement();
|
||||
md.update(ifc.toString().getBytes());
|
||||
if (!ifc.isVirtual()) { // skip fake addresses
|
||||
byte[] bs = ifc.getHardwareAddress();
|
||||
if (bs != null) {
|
||||
md.update(bs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to convert a long into a byte array (least significant
|
||||
* byte first).
|
||||
*/
|
||||
private static byte[] longToByteArray(long l) {
|
||||
byte[] retVal = new byte[8];
|
||||
|
||||
for (int i=0; i<8; i++) {
|
||||
retVal[i] = (byte) l;
|
||||
l >>= 8;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/*
|
||||
// This method helps the test utility receive unprocessed seed bytes.
|
||||
public static int genTestSeed() {
|
||||
return myself.getByte();
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
private static class ThreadedSeedGenerator extends SeedGenerator
|
||||
implements Runnable {
|
||||
// Queue is used to collect seed bytes
|
||||
private byte[] pool;
|
||||
private int start, end, count;
|
||||
|
||||
// Thread group for our threads
|
||||
ThreadGroup seedGroup;
|
||||
|
||||
/**
|
||||
* The constructor is only called once to construct the one
|
||||
* instance we actually use. It instantiates the message digest
|
||||
* and starts the thread going.
|
||||
*/
|
||||
ThreadedSeedGenerator() {
|
||||
pool = new byte[20];
|
||||
start = end = 0;
|
||||
|
||||
MessageDigest digest;
|
||||
|
||||
try {
|
||||
digest = MessageDigest.getInstance("SHA");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new InternalError("internal error: SHA-1 not available."
|
||||
, e);
|
||||
}
|
||||
|
||||
final ThreadGroup[] finalsg = new ThreadGroup[1];
|
||||
Thread t = java.security.AccessController.doPrivileged
|
||||
(new java.security.PrivilegedAction<Thread>() {
|
||||
@Override
|
||||
public Thread run() {
|
||||
ThreadGroup parent, group =
|
||||
Thread.currentThread().getThreadGroup();
|
||||
while ((parent = group.getParent()) != null) {
|
||||
group = parent;
|
||||
}
|
||||
finalsg[0] = new ThreadGroup
|
||||
(group, "SeedGenerator ThreadGroup");
|
||||
Thread newT = new Thread(finalsg[0],
|
||||
ThreadedSeedGenerator.this,
|
||||
"SeedGenerator Thread");
|
||||
newT.setPriority(Thread.MIN_PRIORITY);
|
||||
newT.setDaemon(true);
|
||||
return newT;
|
||||
}
|
||||
});
|
||||
seedGroup = finalsg[0];
|
||||
t.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method does the actual work. It collects random bytes and
|
||||
* pushes them into the queue.
|
||||
*/
|
||||
@Override
|
||||
final public void run() {
|
||||
try {
|
||||
while (true) {
|
||||
// Queue full? Wait till there's room.
|
||||
synchronized(this) {
|
||||
while (count >= pool.length) {
|
||||
wait();
|
||||
}
|
||||
}
|
||||
|
||||
int counter, quanta;
|
||||
byte v = 0;
|
||||
|
||||
// Spin count must not be under 64000
|
||||
for (counter = quanta = 0;
|
||||
(counter < 64000) && (quanta < 6); quanta++) {
|
||||
|
||||
// Start some noisy threads
|
||||
try {
|
||||
BogusThread bt = new BogusThread();
|
||||
Thread t = new Thread
|
||||
(seedGroup, bt, "SeedGenerator Thread");
|
||||
t.start();
|
||||
} catch (Exception e) {
|
||||
throw new InternalError("internal error: " +
|
||||
"SeedGenerator thread creation error.", e);
|
||||
}
|
||||
|
||||
// We wait 250milli quanta, so the minimum wait time
|
||||
// cannot be under 250milli.
|
||||
int latch = 0;
|
||||
long l = System.currentTimeMillis() + 250;
|
||||
while (System.currentTimeMillis() < l) {
|
||||
synchronized(this){};
|
||||
latch++;
|
||||
}
|
||||
|
||||
// Translate the value using the permutation, and xor
|
||||
// it with previous values gathered.
|
||||
v ^= rndTab[latch % 255];
|
||||
counter += latch;
|
||||
}
|
||||
|
||||
// Push it into the queue and notify anybody who might
|
||||
// be waiting for it.
|
||||
synchronized(this) {
|
||||
pool[end] = v;
|
||||
end++;
|
||||
count++;
|
||||
if (end >= pool.length) {
|
||||
end = 0;
|
||||
}
|
||||
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new InternalError("internal error: " +
|
||||
"SeedGenerator thread generated an exception.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void getSeedBytes(byte[] result) {
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = getSeedByte();
|
||||
}
|
||||
}
|
||||
|
||||
byte getSeedByte() {
|
||||
byte b;
|
||||
|
||||
try {
|
||||
// Wait for it...
|
||||
synchronized(this) {
|
||||
while (count <= 0) {
|
||||
wait();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (count <= 0) {
|
||||
throw new InternalError("internal error: " +
|
||||
"SeedGenerator thread generated an exception.", e);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized(this) {
|
||||
// Get it from the queue
|
||||
b = pool[start];
|
||||
pool[start] = 0;
|
||||
start++;
|
||||
count--;
|
||||
if (start == pool.length) {
|
||||
start = 0;
|
||||
}
|
||||
|
||||
// Notify the daemon thread, just in case it is
|
||||
// waiting for us to make room in the queue.
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
// The permutation was calculated by generating 64k of random
|
||||
// data and using it to mix the trivial permutation.
|
||||
// It should be evenly distributed. The specific values
|
||||
// are not crucial to the security of this class.
|
||||
private static byte[] rndTab = {
|
||||
56, 30, -107, -6, -86, 25, -83, 75, -12, -64,
|
||||
5, -128, 78, 21, 16, 32, 70, -81, 37, -51,
|
||||
-43, -46, -108, 87, 29, 17, -55, 22, -11, -111,
|
||||
-115, 84, -100, 108, -45, -15, -98, 72, -33, -28,
|
||||
31, -52, -37, -117, -97, -27, 93, -123, 47, 126,
|
||||
-80, -62, -93, -79, 61, -96, -65, -5, -47, -119,
|
||||
14, 89, 81, -118, -88, 20, 67, -126, -113, 60,
|
||||
-102, 55, 110, 28, 85, 121, 122, -58, 2, 45,
|
||||
43, 24, -9, 103, -13, 102, -68, -54, -101, -104,
|
||||
19, 13, -39, -26, -103, 62, 77, 51, 44, 111,
|
||||
73, 18, -127, -82, 4, -30, 11, -99, -74, 40,
|
||||
-89, 42, -76, -77, -94, -35, -69, 35, 120, 76,
|
||||
33, -73, -7, 82, -25, -10, 88, 125, -112, 58,
|
||||
83, 95, 6, 10, 98, -34, 80, 15, -91, 86,
|
||||
-19, 52, -17, 117, 49, -63, 118, -90, 36, -116,
|
||||
-40, -71, 97, -53, -109, -85, 109, -16, -3, 104,
|
||||
-95, 68, 54, 34, 26, 114, -1, 106, -121, 3,
|
||||
66, 0, 100, -84, 57, 107, 119, -42, 112, -61,
|
||||
1, 48, 38, 12, -56, -57, 39, -106, -72, 41,
|
||||
7, 71, -29, -59, -8, -38, 79, -31, 124, -124,
|
||||
8, 91, 116, 99, -4, 9, -36, -78, 63, -49,
|
||||
-67, -87, 59, 101, -32, 92, 94, 53, -41, 115,
|
||||
-66, -70, -122, 50, -50, -22, -20, -18, -21, 23,
|
||||
-2, -48, 96, 65, -105, 123, -14, -110, 69, -24,
|
||||
-120, -75, 74, 127, -60, 113, 90, -114, 105, 46,
|
||||
27, -125, -23, -44, 64
|
||||
};
|
||||
|
||||
/**
|
||||
* This inner thread causes the thread scheduler to become 'noisy',
|
||||
* thus adding entropy to the system load.
|
||||
* At least one instance of this class is generated for every seed byte.
|
||||
*/
|
||||
private static class BogusThread implements Runnable {
|
||||
@Override
|
||||
final public void run() {
|
||||
try {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
Thread.sleep(50);
|
||||
}
|
||||
// System.gc();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class URLSeedGenerator extends SeedGenerator {
|
||||
|
||||
private String deviceName;
|
||||
private InputStream seedStream;
|
||||
|
||||
/**
|
||||
* The constructor is only called once to construct the one
|
||||
* instance we actually use. It opens the entropy gathering device
|
||||
* which will supply the randomness.
|
||||
*/
|
||||
|
||||
URLSeedGenerator(String egdurl) throws IOException {
|
||||
if (egdurl == null) {
|
||||
throw new IOException("No random source specified");
|
||||
}
|
||||
deviceName = egdurl;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() throws IOException {
|
||||
final URL device = new URL(deviceName);
|
||||
try {
|
||||
seedStream = java.security.AccessController.doPrivileged
|
||||
(new java.security.PrivilegedExceptionAction<InputStream>() {
|
||||
@Override
|
||||
public InputStream run() throws IOException {
|
||||
/*
|
||||
* return a FileInputStream for file URLs and
|
||||
* avoid buffering. The openStream() call wraps
|
||||
* InputStream in a BufferedInputStream which
|
||||
* can buffer up to 8K bytes. This read is a
|
||||
* performance issue for entropy sources which
|
||||
* can be slow to replenish.
|
||||
*/
|
||||
if (device.getProtocol().equalsIgnoreCase("file")) {
|
||||
File deviceFile =
|
||||
SunEntries.getDeviceFile(device);
|
||||
return new FileInputStream(deviceFile);
|
||||
} else {
|
||||
return device.openStream();
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
throw new IOException(
|
||||
"Failed to open " + deviceName, e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void getSeedBytes(byte[] result) {
|
||||
int len = result.length;
|
||||
int read = 0;
|
||||
try {
|
||||
while (read < len) {
|
||||
int count = seedStream.read(result, read, len - read);
|
||||
// /dev/random blocks - should never have EOF
|
||||
if (count < 0) {
|
||||
throw new InternalError(
|
||||
"URLSeedGenerator " + deviceName +
|
||||
" reached end of file");
|
||||
}
|
||||
read += count;
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new InternalError("URLSeedGenerator " + deviceName +
|
||||
" generated exception: " + ioe.getMessage(), ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
401
jdkSrc/jdk8/sun/security/provider/SubjectCodeSource.java
Normal file
401
jdkSrc/jdk8/sun/security/provider/SubjectCodeSource.java
Normal file
@@ -0,0 +1,401 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.security.CodeSource;
|
||||
import java.security.Principal;
|
||||
import java.security.cert.Certificate;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
import sun.security.provider.PolicyParser.PrincipalEntry;
|
||||
|
||||
/**
|
||||
* <p> This <code>SubjectCodeSource</code> class contains
|
||||
* a <code>URL</code>, signer certificates, and either a <code>Subject</code>
|
||||
* (that represents the <code>Subject</code> in the current
|
||||
* <code>AccessControlContext</code>), or a linked list of Principals
|
||||
* (that represent a "subject" in a <code>Policy</code>).
|
||||
*
|
||||
*/
|
||||
class SubjectCodeSource extends CodeSource implements java.io.Serializable {
|
||||
|
||||
private static final long serialVersionUID = 6039418085604715275L;
|
||||
|
||||
private static final java.util.ResourceBundle rb =
|
||||
java.security.AccessController.doPrivileged
|
||||
(new java.security.PrivilegedAction<java.util.ResourceBundle>() {
|
||||
public java.util.ResourceBundle run() {
|
||||
return (java.util.ResourceBundle.getBundle
|
||||
("sun.security.util.AuthResources"));
|
||||
}
|
||||
});
|
||||
|
||||
private Subject subject;
|
||||
private LinkedList<PrincipalEntry> principals;
|
||||
private static final Class<?>[] PARAMS = { String.class };
|
||||
private static final sun.security.util.Debug debug =
|
||||
sun.security.util.Debug.getInstance("auth", "\t[Auth Access]");
|
||||
private ClassLoader sysClassLoader;
|
||||
|
||||
/**
|
||||
* Creates a new <code>SubjectCodeSource</code>
|
||||
* with the given <code>Subject</code>, principals, <code>URL</code>,
|
||||
* and signers (Certificates). The <code>Subject</code>
|
||||
* represents the <code>Subject</code> associated with the current
|
||||
* <code>AccessControlContext</code>.
|
||||
* The Principals are given as a <code>LinkedList</code>
|
||||
* of <code>PolicyParser.PrincipalEntry</code> objects.
|
||||
* Typically either a <code>Subject</code> will be provided,
|
||||
* or a list of <code>principals</code> will be provided
|
||||
* (not both).
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
* @param subject the <code>Subject</code> associated with this
|
||||
* <code>SubjectCodeSource</code> <p>
|
||||
*
|
||||
* @param url the <code>URL</code> associated with this
|
||||
* <code>SubjectCodeSource</code> <p>
|
||||
*
|
||||
* @param certs the signers associated with this
|
||||
* <code>SubjectCodeSource</code> <p>
|
||||
*/
|
||||
SubjectCodeSource(Subject subject,
|
||||
LinkedList<PrincipalEntry> principals,
|
||||
URL url, Certificate[] certs) {
|
||||
|
||||
super(url, certs);
|
||||
this.subject = subject;
|
||||
this.principals = (principals == null ?
|
||||
new LinkedList<PrincipalEntry>() :
|
||||
new LinkedList<PrincipalEntry>(principals));
|
||||
sysClassLoader = java.security.AccessController.doPrivileged
|
||||
(new java.security.PrivilegedAction<ClassLoader>() {
|
||||
public ClassLoader run() {
|
||||
return ClassLoader.getSystemClassLoader();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Principals associated with this <code>SubjectCodeSource</code>.
|
||||
* The Principals are retrieved as a <code>LinkedList</code>
|
||||
* of <code>PolicyParser.PrincipalEntry</code> objects.
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
* @return the Principals associated with this
|
||||
* <code>SubjectCodeSource</code> as a <code>LinkedList</code>
|
||||
* of <code>PolicyParser.PrincipalEntry</code> objects.
|
||||
*/
|
||||
LinkedList<PrincipalEntry> getPrincipals() {
|
||||
return principals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the <code>Subject</code> associated with this
|
||||
* <code>SubjectCodeSource</code>. The <code>Subject</code>
|
||||
* represents the <code>Subject</code> associated with the
|
||||
* current <code>AccessControlContext</code>.
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
* @return the <code>Subject</code> associated with this
|
||||
* <code>SubjectCodeSource</code>.
|
||||
*/
|
||||
Subject getSubject() {
|
||||
return subject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this <code>SubjectCodeSource</code> object "implies"
|
||||
* the specified <code>CodeSource</code>.
|
||||
* More specifically, this method makes the following checks.
|
||||
* If any fail, it returns false. If they all succeed, it returns true.
|
||||
*
|
||||
* <p>
|
||||
* <ol>
|
||||
* <li> The provided codesource must not be <code>null</code>.
|
||||
* <li> codesource must be an instance of <code>SubjectCodeSource</code>.
|
||||
* <li> super.implies(codesource) must return true.
|
||||
* <li> for each principal in this codesource's principal list:
|
||||
* <ol>
|
||||
* <li> if the principal is an instanceof
|
||||
* <code>Principal</code>, then the principal must
|
||||
* imply the provided codesource's <code>Subject</code>.
|
||||
* <li> if the principal is not an instanceof
|
||||
* <code>Principal</code>, then the provided
|
||||
* codesource's <code>Subject</code> must have an
|
||||
* associated <code>Principal</code>, <i>P</i>, where
|
||||
* P.getClass().getName equals principal.principalClass,
|
||||
* and P.getName() equals principal.principalName.
|
||||
* </ol>
|
||||
* </ol>
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
* @param codesource the <code>CodeSource</code> to compare against.
|
||||
*
|
||||
* @return true if this <code>SubjectCodeSource</code> implies the
|
||||
* the specified <code>CodeSource</code>.
|
||||
*/
|
||||
public boolean implies(CodeSource codesource) {
|
||||
|
||||
LinkedList<PrincipalEntry> subjectList = null;
|
||||
|
||||
if (codesource == null ||
|
||||
!(codesource instanceof SubjectCodeSource) ||
|
||||
!(super.implies(codesource))) {
|
||||
|
||||
if (debug != null)
|
||||
debug.println("\tSubjectCodeSource.implies: FAILURE 1");
|
||||
return false;
|
||||
}
|
||||
|
||||
SubjectCodeSource that = (SubjectCodeSource)codesource;
|
||||
|
||||
// if the principal list in the policy "implies"
|
||||
// the Subject associated with the current AccessControlContext,
|
||||
// then return true
|
||||
|
||||
if (this.principals == null) {
|
||||
if (debug != null)
|
||||
debug.println("\tSubjectCodeSource.implies: PASS 1");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (that.getSubject() == null ||
|
||||
that.getSubject().getPrincipals().size() == 0) {
|
||||
if (debug != null)
|
||||
debug.println("\tSubjectCodeSource.implies: FAILURE 2");
|
||||
return false;
|
||||
}
|
||||
|
||||
ListIterator<PrincipalEntry> li = this.principals.listIterator(0);
|
||||
while (li.hasNext()) {
|
||||
PrincipalEntry pppe = li.next();
|
||||
try {
|
||||
|
||||
// use new Principal.implies method
|
||||
|
||||
Class<?> pClass = Class.forName(pppe.principalClass,
|
||||
true, sysClassLoader);
|
||||
if (!Principal.class.isAssignableFrom(pClass)) {
|
||||
// not the right subtype
|
||||
throw new ClassCastException(pppe.principalClass +
|
||||
" is not a Principal");
|
||||
}
|
||||
Constructor<?> c = pClass.getConstructor(PARAMS);
|
||||
Principal p = (Principal)c.newInstance(new Object[] {
|
||||
pppe.principalName });
|
||||
|
||||
if (!p.implies(that.getSubject())) {
|
||||
if (debug != null)
|
||||
debug.println("\tSubjectCodeSource.implies: FAILURE 3");
|
||||
return false;
|
||||
} else {
|
||||
if (debug != null)
|
||||
debug.println("\tSubjectCodeSource.implies: PASS 2");
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
// simply compare Principals
|
||||
|
||||
if (subjectList == null) {
|
||||
|
||||
if (that.getSubject() == null) {
|
||||
if (debug != null)
|
||||
debug.println("\tSubjectCodeSource.implies: " +
|
||||
"FAILURE 4");
|
||||
return false;
|
||||
}
|
||||
Iterator<Principal> i =
|
||||
that.getSubject().getPrincipals().iterator();
|
||||
|
||||
subjectList = new LinkedList<PrincipalEntry>();
|
||||
while (i.hasNext()) {
|
||||
Principal p = i.next();
|
||||
PrincipalEntry spppe = new PrincipalEntry
|
||||
(p.getClass().getName(), p.getName());
|
||||
subjectList.add(spppe);
|
||||
}
|
||||
}
|
||||
|
||||
if (!subjectListImpliesPrincipalEntry(subjectList, pppe)) {
|
||||
if (debug != null)
|
||||
debug.println("\tSubjectCodeSource.implies: FAILURE 5");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (debug != null)
|
||||
debug.println("\tSubjectCodeSource.implies: PASS 3");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns, true, if the provided <i>subjectList</i>
|
||||
* "contains" the <code>Principal</code> specified
|
||||
* in the provided <i>pppe</i> argument.
|
||||
*
|
||||
* Note that the provided <i>pppe</i> argument may have
|
||||
* wildcards (*) for the <code>Principal</code> class and name,
|
||||
* which need to be considered.
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
* @param subjectList a list of PolicyParser.PrincipalEntry objects
|
||||
* that correspond to all the Principals in the Subject currently
|
||||
* on this thread's AccessControlContext. <p>
|
||||
*
|
||||
* @param pppe the Principals specified in a grant entry.
|
||||
*
|
||||
* @return true if the provided <i>subjectList</i> "contains"
|
||||
* the <code>Principal</code> specified in the provided
|
||||
* <i>pppe</i> argument.
|
||||
*/
|
||||
private boolean subjectListImpliesPrincipalEntry(
|
||||
LinkedList<PrincipalEntry> subjectList, PrincipalEntry pppe) {
|
||||
|
||||
ListIterator<PrincipalEntry> li = subjectList.listIterator(0);
|
||||
while (li.hasNext()) {
|
||||
PrincipalEntry listPppe = li.next();
|
||||
|
||||
if (pppe.getPrincipalClass().equals
|
||||
(PrincipalEntry.WILDCARD_CLASS) ||
|
||||
pppe.getPrincipalClass().equals(listPppe.getPrincipalClass()))
|
||||
{
|
||||
if (pppe.getPrincipalName().equals
|
||||
(PrincipalEntry.WILDCARD_NAME) ||
|
||||
pppe.getPrincipalName().equals(listPppe.getPrincipalName()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for equality between the specified object and this
|
||||
* object. Two <code>SubjectCodeSource</code> objects are considered equal
|
||||
* if their locations are of identical value, if the two sets of
|
||||
* Certificates are of identical values, and if the
|
||||
* Subjects are equal, and if the PolicyParser.PrincipalEntry values
|
||||
* are of identical values. It is not required that
|
||||
* the Certificates or PolicyParser.PrincipalEntry values
|
||||
* be in the same order.
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
* @param obj the object to test for equality with this object.
|
||||
*
|
||||
* @return true if the objects are considered equal, false otherwise.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (obj == this)
|
||||
return true;
|
||||
|
||||
if (super.equals(obj) == false)
|
||||
return false;
|
||||
|
||||
if (!(obj instanceof SubjectCodeSource))
|
||||
return false;
|
||||
|
||||
SubjectCodeSource that = (SubjectCodeSource)obj;
|
||||
|
||||
// the principal lists must match
|
||||
try {
|
||||
if (this.getSubject() != that.getSubject())
|
||||
return false;
|
||||
} catch (SecurityException se) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((this.principals == null && that.principals != null) ||
|
||||
(this.principals != null && that.principals == null))
|
||||
return false;
|
||||
|
||||
if (this.principals != null && that.principals != null) {
|
||||
if (!this.principals.containsAll(that.principals) ||
|
||||
!that.principals.containsAll(this.principals))
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hashcode for this <code>SubjectCodeSource</code>.
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
* @return a hashcode for this <code>SubjectCodeSource</code>.
|
||||
*/
|
||||
public int hashCode() {
|
||||
return super.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a String representation of this <code>SubjectCodeSource</code>.
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
* @return a String representation of this <code>SubjectCodeSource</code>.
|
||||
*/
|
||||
public String toString() {
|
||||
String returnMe = super.toString();
|
||||
if (getSubject() != null) {
|
||||
if (debug != null) {
|
||||
final Subject finalSubject = getSubject();
|
||||
returnMe = returnMe + "\n" +
|
||||
java.security.AccessController.doPrivileged
|
||||
(new java.security.PrivilegedAction<String>() {
|
||||
public String run() {
|
||||
return finalSubject.toString();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
returnMe = returnMe + "\n" + getSubject().toString();
|
||||
}
|
||||
}
|
||||
if (principals != null) {
|
||||
ListIterator<PrincipalEntry> li = principals.listIterator();
|
||||
while (li.hasNext()) {
|
||||
PrincipalEntry pppe = li.next();
|
||||
returnMe = returnMe + rb.getString("NEWLINE") +
|
||||
pppe.getPrincipalClass() + " " +
|
||||
pppe.getPrincipalName();
|
||||
}
|
||||
}
|
||||
return returnMe;
|
||||
}
|
||||
}
|
||||
65
jdkSrc/jdk8/sun/security/provider/Sun.java
Normal file
65
jdkSrc/jdk8/sun/security/provider/Sun.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.util.*;
|
||||
import java.security.*;
|
||||
|
||||
import sun.security.action.PutAllAction;
|
||||
|
||||
/**
|
||||
* The SUN Security Provider.
|
||||
*
|
||||
*/
|
||||
public final class Sun extends Provider {
|
||||
|
||||
private static final long serialVersionUID = 6440182097568097204L;
|
||||
|
||||
private static final String INFO = "SUN " +
|
||||
"(DSA key/parameter generation; DSA signing; SHA-1, MD5 digests; " +
|
||||
"SecureRandom; X.509 certificates; JKS & DKS keystores; " +
|
||||
"PKIX CertPathValidator; " +
|
||||
"PKIX CertPathBuilder; LDAP, Collection CertStores, JavaPolicy Policy; " +
|
||||
"JavaLoginConfig Configuration)";
|
||||
|
||||
public Sun() {
|
||||
/* We are the SUN provider */
|
||||
super("SUN", 1.8d, INFO);
|
||||
|
||||
// if there is no security manager installed, put directly into
|
||||
// the provider. Otherwise, create a temporary map and use a
|
||||
// doPrivileged() call at the end to transfer the contents
|
||||
if (System.getSecurityManager() == null) {
|
||||
SunEntries.putEntries(this);
|
||||
} else {
|
||||
// use LinkedHashMap to preserve the order of the PRNGs
|
||||
Map<Object, Object> map = new LinkedHashMap<>();
|
||||
SunEntries.putEntries(map);
|
||||
AccessController.doPrivileged(new PutAllAction(this, map));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
389
jdkSrc/jdk8/sun/security/provider/SunEntries.java
Normal file
389
jdkSrc/jdk8/sun/security/provider/SunEntries.java
Normal file
@@ -0,0 +1,389 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.Map;
|
||||
import java.security.*;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
* Defines the entries of the SUN provider.
|
||||
*
|
||||
* Algorithms supported, and their names:
|
||||
*
|
||||
* - SHA is the message digest scheme described in FIPS 180-1.
|
||||
* Aliases for SHA are SHA-1 and SHA1.
|
||||
*
|
||||
* - SHA1withDSA is the signature scheme described in FIPS 186.
|
||||
* (SHA used in DSA is SHA-1: FIPS 186 with Change No 1.)
|
||||
* Aliases for SHA1withDSA are DSA, DSS, SHA/DSA, SHA-1/DSA, SHA1/DSA,
|
||||
* SHAwithDSA, DSAWithSHA1, and the object
|
||||
* identifier strings "OID.1.3.14.3.2.13", "OID.1.3.14.3.2.27" and
|
||||
* "OID.1.2.840.10040.4.3".
|
||||
*
|
||||
* - SHA-2 is a set of message digest schemes described in FIPS 180-2.
|
||||
* SHA-2 family of hash functions includes SHA-224, SHA-256, SHA-384,
|
||||
* and SHA-512.
|
||||
*
|
||||
* - SHA-224withDSA/SHA-256withDSA are the signature schemes
|
||||
* described in FIPS 186-3. The associated object identifiers are
|
||||
* "OID.2.16.840.1.101.3.4.3.1", and "OID.2.16.840.1.101.3.4.3.2".
|
||||
|
||||
* - DSA is the key generation scheme as described in FIPS 186.
|
||||
* Aliases for DSA include the OID strings "OID.1.3.14.3.2.12"
|
||||
* and "OID.1.2.840.10040.4.1".
|
||||
*
|
||||
* - MD5 is the message digest scheme described in RFC 1321.
|
||||
* There are no aliases for MD5.
|
||||
*
|
||||
* - X.509 is the certificate factory type for X.509 certificates
|
||||
* and CRLs. Aliases for X.509 are X509.
|
||||
*
|
||||
* - PKIX is the certification path validation algorithm described
|
||||
* in RFC 5280. The ValidationAlgorithm attribute notes the
|
||||
* specification that this provider implements.
|
||||
*
|
||||
* - LDAP is the CertStore type for LDAP repositories. The
|
||||
* LDAPSchema attribute notes the specification defining the
|
||||
* schema that this provider uses to find certificates and CRLs.
|
||||
*
|
||||
* - JavaPolicy is the default file-based Policy type.
|
||||
*
|
||||
* - JavaLoginConfig is the default file-based LoginModule Configuration type.
|
||||
*/
|
||||
|
||||
final class SunEntries {
|
||||
|
||||
private static final boolean useLegacyDSA =
|
||||
Boolean.parseBoolean(GetPropertyAction.privilegedGetProperty
|
||||
("jdk.security.legacyDSAKeyPairGenerator"));
|
||||
|
||||
private SunEntries() {
|
||||
// empty
|
||||
}
|
||||
|
||||
static void putEntries(Map<Object, Object> map) {
|
||||
|
||||
/*
|
||||
* SecureRandom
|
||||
*
|
||||
* Register these first to speed up "new SecureRandom()",
|
||||
* which iterates through the list of algorithms
|
||||
*/
|
||||
// register the native PRNG, if available
|
||||
// if user selected /dev/urandom, we put it before SHA1PRNG,
|
||||
// otherwise after it
|
||||
boolean nativeAvailable = NativePRNG.isAvailable();
|
||||
boolean useNativePRNG = seedSource.equals(URL_DEV_URANDOM) ||
|
||||
seedSource.equals(URL_DEV_RANDOM);
|
||||
|
||||
if (nativeAvailable && useNativePRNG) {
|
||||
map.put("SecureRandom.NativePRNG",
|
||||
"sun.security.provider.NativePRNG");
|
||||
}
|
||||
|
||||
map.put("SecureRandom.SHA1PRNG",
|
||||
"sun.security.provider.SecureRandom");
|
||||
if (nativeAvailable && !useNativePRNG) {
|
||||
map.put("SecureRandom.NativePRNG",
|
||||
"sun.security.provider.NativePRNG");
|
||||
}
|
||||
|
||||
if (NativePRNG.Blocking.isAvailable()) {
|
||||
map.put("SecureRandom.NativePRNGBlocking",
|
||||
"sun.security.provider.NativePRNG$Blocking");
|
||||
}
|
||||
|
||||
if (NativePRNG.NonBlocking.isAvailable()) {
|
||||
map.put("SecureRandom.NativePRNGNonBlocking",
|
||||
"sun.security.provider.NativePRNG$NonBlocking");
|
||||
}
|
||||
|
||||
/*
|
||||
* Signature engines
|
||||
*/
|
||||
map.put("Signature.SHA1withDSA",
|
||||
"sun.security.provider.DSA$SHA1withDSA");
|
||||
map.put("Signature.NONEwithDSA", "sun.security.provider.DSA$RawDSA");
|
||||
map.put("Alg.Alias.Signature.RawDSA", "NONEwithDSA");
|
||||
map.put("Signature.SHA224withDSA",
|
||||
"sun.security.provider.DSA$SHA224withDSA");
|
||||
map.put("Signature.SHA256withDSA",
|
||||
"sun.security.provider.DSA$SHA256withDSA");
|
||||
|
||||
String dsaKeyClasses = "java.security.interfaces.DSAPublicKey" +
|
||||
"|java.security.interfaces.DSAPrivateKey";
|
||||
map.put("Signature.SHA1withDSA SupportedKeyClasses", dsaKeyClasses);
|
||||
map.put("Signature.NONEwithDSA SupportedKeyClasses", dsaKeyClasses);
|
||||
map.put("Signature.SHA224withDSA SupportedKeyClasses", dsaKeyClasses);
|
||||
map.put("Signature.SHA256withDSA SupportedKeyClasses", dsaKeyClasses);
|
||||
|
||||
map.put("Alg.Alias.Signature.DSA", "SHA1withDSA");
|
||||
map.put("Alg.Alias.Signature.DSS", "SHA1withDSA");
|
||||
map.put("Alg.Alias.Signature.SHA/DSA", "SHA1withDSA");
|
||||
map.put("Alg.Alias.Signature.SHA-1/DSA", "SHA1withDSA");
|
||||
map.put("Alg.Alias.Signature.SHA1/DSA", "SHA1withDSA");
|
||||
map.put("Alg.Alias.Signature.SHAwithDSA", "SHA1withDSA");
|
||||
map.put("Alg.Alias.Signature.DSAWithSHA1", "SHA1withDSA");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.10040.4.3",
|
||||
"SHA1withDSA");
|
||||
map.put("Alg.Alias.Signature.1.2.840.10040.4.3", "SHA1withDSA");
|
||||
map.put("Alg.Alias.Signature.1.3.14.3.2.13", "SHA1withDSA");
|
||||
map.put("Alg.Alias.Signature.1.3.14.3.2.27", "SHA1withDSA");
|
||||
map.put("Alg.Alias.Signature.OID.2.16.840.1.101.3.4.3.1",
|
||||
"SHA224withDSA");
|
||||
map.put("Alg.Alias.Signature.2.16.840.1.101.3.4.3.1", "SHA224withDSA");
|
||||
map.put("Alg.Alias.Signature.OID.2.16.840.1.101.3.4.3.2",
|
||||
"SHA256withDSA");
|
||||
map.put("Alg.Alias.Signature.2.16.840.1.101.3.4.3.2", "SHA256withDSA");
|
||||
|
||||
/*
|
||||
* Key Pair Generator engines
|
||||
*/
|
||||
String dsaKPGImplClass = "sun.security.provider.DSAKeyPairGenerator$";
|
||||
dsaKPGImplClass += (useLegacyDSA? "Legacy" : "Current");
|
||||
map.put("KeyPairGenerator.DSA", dsaKPGImplClass);
|
||||
map.put("Alg.Alias.KeyPairGenerator.OID.1.2.840.10040.4.1", "DSA");
|
||||
map.put("Alg.Alias.KeyPairGenerator.1.2.840.10040.4.1", "DSA");
|
||||
map.put("Alg.Alias.KeyPairGenerator.1.3.14.3.2.12", "DSA");
|
||||
|
||||
/*
|
||||
* Digest engines
|
||||
*/
|
||||
map.put("MessageDigest.MD2", "sun.security.provider.MD2");
|
||||
map.put("MessageDigest.MD5", "sun.security.provider.MD5");
|
||||
map.put("MessageDigest.SHA", "sun.security.provider.SHA");
|
||||
|
||||
map.put("Alg.Alias.MessageDigest.SHA-1", "SHA");
|
||||
map.put("Alg.Alias.MessageDigest.SHA1", "SHA");
|
||||
map.put("Alg.Alias.MessageDigest.1.3.14.3.2.26", "SHA");
|
||||
map.put("Alg.Alias.MessageDigest.OID.1.3.14.3.2.26", "SHA");
|
||||
|
||||
map.put("MessageDigest.SHA-224", "sun.security.provider.SHA2$SHA224");
|
||||
map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.4", "SHA-224");
|
||||
map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.4",
|
||||
"SHA-224");
|
||||
|
||||
map.put("MessageDigest.SHA-256", "sun.security.provider.SHA2$SHA256");
|
||||
map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.1", "SHA-256");
|
||||
map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.1",
|
||||
"SHA-256");
|
||||
map.put("MessageDigest.SHA-384", "sun.security.provider.SHA5$SHA384");
|
||||
map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.2", "SHA-384");
|
||||
map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.2",
|
||||
"SHA-384");
|
||||
map.put("MessageDigest.SHA-512", "sun.security.provider.SHA5$SHA512");
|
||||
map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.3", "SHA-512");
|
||||
map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.3",
|
||||
"SHA-512");
|
||||
map.put("MessageDigest.SHA-512/224", "sun.security.provider.SHA5$SHA512_224");
|
||||
map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.5", "SHA-512/224");
|
||||
map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.5",
|
||||
"SHA-512/224");
|
||||
map.put("MessageDigest.SHA-512/256", "sun.security.provider.SHA5$SHA512_256");
|
||||
map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.6", "SHA-512/256");
|
||||
map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.6",
|
||||
"SHA-512/256");
|
||||
|
||||
/*
|
||||
* Algorithm Parameter Generator engines
|
||||
*/
|
||||
map.put("AlgorithmParameterGenerator.DSA",
|
||||
"sun.security.provider.DSAParameterGenerator");
|
||||
|
||||
/*
|
||||
* Algorithm Parameter engines
|
||||
*/
|
||||
map.put("AlgorithmParameters.DSA",
|
||||
"sun.security.provider.DSAParameters");
|
||||
map.put("Alg.Alias.AlgorithmParameters.OID.1.2.840.10040.4.1", "DSA");
|
||||
map.put("Alg.Alias.AlgorithmParameters.1.2.840.10040.4.1", "DSA");
|
||||
map.put("Alg.Alias.AlgorithmParameters.1.3.14.3.2.12", "DSA");
|
||||
|
||||
/*
|
||||
* Key factories
|
||||
*/
|
||||
map.put("KeyFactory.DSA", "sun.security.provider.DSAKeyFactory");
|
||||
map.put("Alg.Alias.KeyFactory.OID.1.2.840.10040.4.1", "DSA");
|
||||
map.put("Alg.Alias.KeyFactory.1.2.840.10040.4.1", "DSA");
|
||||
map.put("Alg.Alias.KeyFactory.1.3.14.3.2.12", "DSA");
|
||||
|
||||
/*
|
||||
* Certificates
|
||||
*/
|
||||
map.put("CertificateFactory.X.509",
|
||||
"sun.security.provider.X509Factory");
|
||||
map.put("Alg.Alias.CertificateFactory.X509", "X.509");
|
||||
|
||||
/*
|
||||
* KeyStore
|
||||
*/
|
||||
map.put("KeyStore.JKS",
|
||||
"sun.security.provider.JavaKeyStore$DualFormatJKS");
|
||||
map.put("KeyStore.CaseExactJKS",
|
||||
"sun.security.provider.JavaKeyStore$CaseExactJKS");
|
||||
map.put("KeyStore.DKS", "sun.security.provider.DomainKeyStore$DKS");
|
||||
|
||||
/*
|
||||
* Policy
|
||||
*/
|
||||
map.put("Policy.JavaPolicy", "sun.security.provider.PolicySpiFile");
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
map.put("Configuration.JavaLoginConfig",
|
||||
"sun.security.provider.ConfigFile$Spi");
|
||||
|
||||
/*
|
||||
* CertPathBuilder
|
||||
*/
|
||||
map.put("CertPathBuilder.PKIX",
|
||||
"sun.security.provider.certpath.SunCertPathBuilder");
|
||||
map.put("CertPathBuilder.PKIX ValidationAlgorithm",
|
||||
"RFC5280");
|
||||
|
||||
/*
|
||||
* CertPathValidator
|
||||
*/
|
||||
map.put("CertPathValidator.PKIX",
|
||||
"sun.security.provider.certpath.PKIXCertPathValidator");
|
||||
map.put("CertPathValidator.PKIX ValidationAlgorithm",
|
||||
"RFC5280");
|
||||
|
||||
/*
|
||||
* CertStores
|
||||
*/
|
||||
map.put("CertStore.LDAP",
|
||||
"sun.security.provider.certpath.ldap.LDAPCertStore");
|
||||
map.put("CertStore.LDAP LDAPSchema", "RFC2587");
|
||||
map.put("CertStore.Collection",
|
||||
"sun.security.provider.certpath.CollectionCertStore");
|
||||
map.put("CertStore.com.sun.security.IndexedCollection",
|
||||
"sun.security.provider.certpath.IndexedCollectionCertStore");
|
||||
|
||||
/*
|
||||
* KeySize
|
||||
*/
|
||||
map.put("Signature.NONEwithDSA KeySize", "1024");
|
||||
map.put("Signature.SHA1withDSA KeySize", "1024");
|
||||
map.put("Signature.SHA224withDSA KeySize", "2048");
|
||||
map.put("Signature.SHA256withDSA KeySize", "2048");
|
||||
|
||||
map.put("KeyPairGenerator.DSA KeySize", "2048");
|
||||
map.put("AlgorithmParameterGenerator.DSA KeySize", "2048");
|
||||
|
||||
/*
|
||||
* Implementation type: software or hardware
|
||||
*/
|
||||
map.put("Signature.SHA1withDSA ImplementedIn", "Software");
|
||||
map.put("KeyPairGenerator.DSA ImplementedIn", "Software");
|
||||
map.put("MessageDigest.MD5 ImplementedIn", "Software");
|
||||
map.put("MessageDigest.SHA ImplementedIn", "Software");
|
||||
map.put("AlgorithmParameterGenerator.DSA ImplementedIn",
|
||||
"Software");
|
||||
map.put("AlgorithmParameters.DSA ImplementedIn", "Software");
|
||||
map.put("KeyFactory.DSA ImplementedIn", "Software");
|
||||
map.put("SecureRandom.SHA1PRNG ImplementedIn", "Software");
|
||||
map.put("CertificateFactory.X.509 ImplementedIn", "Software");
|
||||
map.put("KeyStore.JKS ImplementedIn", "Software");
|
||||
map.put("CertPathValidator.PKIX ImplementedIn", "Software");
|
||||
map.put("CertPathBuilder.PKIX ImplementedIn", "Software");
|
||||
map.put("CertStore.LDAP ImplementedIn", "Software");
|
||||
map.put("CertStore.Collection ImplementedIn", "Software");
|
||||
map.put("CertStore.com.sun.security.IndexedCollection ImplementedIn",
|
||||
"Software");
|
||||
|
||||
}
|
||||
|
||||
// name of the *System* property, takes precedence over PROP_RNDSOURCE
|
||||
private final static String PROP_EGD = "java.security.egd";
|
||||
// name of the *Security* property
|
||||
private final static String PROP_RNDSOURCE = "securerandom.source";
|
||||
|
||||
final static String URL_DEV_RANDOM = "file:/dev/random";
|
||||
final static String URL_DEV_URANDOM = "file:/dev/urandom";
|
||||
|
||||
private static final String seedSource;
|
||||
|
||||
static {
|
||||
seedSource = AccessController.doPrivileged(
|
||||
new PrivilegedAction<String>() {
|
||||
|
||||
@Override
|
||||
public String run() {
|
||||
String egdSource = System.getProperty(PROP_EGD, "");
|
||||
if (egdSource.length() != 0) {
|
||||
return egdSource;
|
||||
}
|
||||
egdSource = Security.getProperty(PROP_RNDSOURCE);
|
||||
if (egdSource == null) {
|
||||
return "";
|
||||
}
|
||||
return egdSource;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static String getSeedSource() {
|
||||
return seedSource;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use a URI to access this File. Previous code used a URL
|
||||
* which is less strict on syntax. If we encounter a
|
||||
* URISyntaxException we make best efforts for backwards
|
||||
* compatibility. e.g. space character in deviceName string.
|
||||
*
|
||||
* Method called within PrivilegedExceptionAction block.
|
||||
*
|
||||
* Moved from SeedGenerator to avoid initialization problems with
|
||||
* signed providers.
|
||||
*/
|
||||
static File getDeviceFile(URL device) throws IOException {
|
||||
try {
|
||||
URI deviceURI = device.toURI();
|
||||
if(deviceURI.isOpaque()) {
|
||||
// File constructor does not accept opaque URI
|
||||
URI localDir = new File(
|
||||
System.getProperty("user.dir")).toURI();
|
||||
String uriPath = localDir.toString() +
|
||||
deviceURI.toString().substring(5);
|
||||
return new File(URI.create(uriPath));
|
||||
} else {
|
||||
return new File(deviceURI);
|
||||
}
|
||||
} catch (URISyntaxException use) {
|
||||
/*
|
||||
* Make best effort to access this File.
|
||||
* We can try using the URL path.
|
||||
*/
|
||||
return new File(device.getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
86
jdkSrc/jdk8/sun/security/provider/VerificationProvider.java
Normal file
86
jdkSrc/jdk8/sun/security/provider/VerificationProvider.java
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.util.*;
|
||||
import java.security.*;
|
||||
|
||||
import sun.security.action.PutAllAction;
|
||||
|
||||
import sun.security.rsa.SunRsaSignEntries;
|
||||
|
||||
/**
|
||||
* Provider used for verification of signed JAR files *if* the Sun and
|
||||
* SunRsaSign main classes have been removed. Otherwise, this provider is not
|
||||
* necessary and registers no algorithms. This functionality only exists to
|
||||
* support a use case required by a specific customer and is not generally
|
||||
* supported.
|
||||
*
|
||||
* @since 1.7
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public final class VerificationProvider extends Provider {
|
||||
|
||||
private static final long serialVersionUID = 7482667077568930381L;
|
||||
|
||||
private static final boolean ACTIVE;
|
||||
|
||||
static {
|
||||
boolean b;
|
||||
try {
|
||||
Class.forName("sun.security.provider.Sun");
|
||||
Class.forName("sun.security.rsa.SunRsaSign");
|
||||
b = false;
|
||||
} catch (ClassNotFoundException e) {
|
||||
b = true;
|
||||
}
|
||||
ACTIVE = b;
|
||||
}
|
||||
|
||||
public VerificationProvider() {
|
||||
super("SunJarVerification", 1.8d, "Jar Verification Provider");
|
||||
// register all algorithms normally registered by the Sun and SunRsaSign
|
||||
// providers, but only if they are missing
|
||||
if (ACTIVE == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if there is no security manager installed, put directly into
|
||||
// the provider. Otherwise, create a temporary map and use a
|
||||
// doPrivileged() call at the end to transfer the contents
|
||||
if (System.getSecurityManager() == null) {
|
||||
SunEntries.putEntries(this);
|
||||
SunRsaSignEntries.putEntries(this);
|
||||
} else {
|
||||
// use LinkedHashMap to preserve the order of the PRNGs
|
||||
Map<Object, Object> map = new LinkedHashMap<>();
|
||||
SunEntries.putEntries(map);
|
||||
SunRsaSignEntries.putEntries(map);
|
||||
AccessController.doPrivileged(new PutAllAction(this, map));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
758
jdkSrc/jdk8/sun/security/provider/X509Factory.java
Normal file
758
jdkSrc/jdk8/sun/security/provider/X509Factory.java
Normal file
@@ -0,0 +1,758 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.security.cert.*;
|
||||
|
||||
import sun.security.util.Pem;
|
||||
import sun.security.x509.X509CertImpl;
|
||||
import sun.security.x509.X509CRLImpl;
|
||||
import sun.security.pkcs.PKCS7;
|
||||
import sun.security.provider.certpath.X509CertPath;
|
||||
import sun.security.provider.certpath.X509CertificatePair;
|
||||
import sun.security.util.DerValue;
|
||||
import sun.security.util.Cache;
|
||||
import java.util.Base64;
|
||||
import sun.security.pkcs.ParsingException;
|
||||
|
||||
/**
|
||||
* This class defines a certificate factory for X.509 v3 certificates &
|
||||
* certification paths, and X.509 v2 certificate revocation lists (CRLs).
|
||||
*
|
||||
* @author Jan Luehe
|
||||
* @author Hemma Prafullchandra
|
||||
* @author Sean Mullan
|
||||
*
|
||||
*
|
||||
* @see java.security.cert.CertificateFactorySpi
|
||||
* @see java.security.cert.Certificate
|
||||
* @see java.security.cert.CertPath
|
||||
* @see java.security.cert.CRL
|
||||
* @see java.security.cert.X509Certificate
|
||||
* @see java.security.cert.X509CRL
|
||||
* @see sun.security.x509.X509CertImpl
|
||||
* @see sun.security.x509.X509CRLImpl
|
||||
*/
|
||||
|
||||
public class X509Factory extends CertificateFactorySpi {
|
||||
|
||||
public static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----";
|
||||
public static final String END_CERT = "-----END CERTIFICATE-----";
|
||||
|
||||
private static final int ENC_MAX_LENGTH = 4096 * 1024; // 4 MB MAX
|
||||
|
||||
private static final Cache<Object, X509CertImpl> certCache
|
||||
= Cache.newSoftMemoryCache(750);
|
||||
private static final Cache<Object, X509CRLImpl> crlCache
|
||||
= Cache.newSoftMemoryCache(750);
|
||||
|
||||
/**
|
||||
* Generates an X.509 certificate object and initializes it with
|
||||
* the data read from the input stream <code>is</code>.
|
||||
*
|
||||
* @param is an input stream with the certificate data.
|
||||
*
|
||||
* @return an X.509 certificate object initialized with the data
|
||||
* from the input stream.
|
||||
*
|
||||
* @exception CertificateException on parsing errors.
|
||||
*/
|
||||
@Override
|
||||
public Certificate engineGenerateCertificate(InputStream is)
|
||||
throws CertificateException
|
||||
{
|
||||
if (is == null) {
|
||||
// clear the caches (for debugging)
|
||||
certCache.clear();
|
||||
X509CertificatePair.clearCache();
|
||||
throw new CertificateException("Missing input stream");
|
||||
}
|
||||
try {
|
||||
byte[] encoding = readOneBlock(is);
|
||||
if (encoding != null) {
|
||||
X509CertImpl cert = getFromCache(certCache, encoding);
|
||||
if (cert != null) {
|
||||
return cert;
|
||||
}
|
||||
cert = new X509CertImpl(encoding);
|
||||
addToCache(certCache, cert.getEncodedInternal(), cert);
|
||||
return cert;
|
||||
} else {
|
||||
throw new IOException("Empty input");
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new CertificateException("Could not parse certificate: " +
|
||||
ioe.toString(), ioe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read from the stream until length bytes have been read or EOF has
|
||||
* been reached. Return the number of bytes actually read.
|
||||
*/
|
||||
private static int readFully(InputStream in, ByteArrayOutputStream bout,
|
||||
int length) throws IOException {
|
||||
int read = 0;
|
||||
byte[] buffer = new byte[2048];
|
||||
while (length > 0) {
|
||||
int n = in.read(buffer, 0, length<2048?length:2048);
|
||||
if (n <= 0) {
|
||||
break;
|
||||
}
|
||||
bout.write(buffer, 0, n);
|
||||
read += n;
|
||||
length -= n;
|
||||
}
|
||||
return read;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an interned X509CertImpl for the given certificate.
|
||||
* If the given X509Certificate or X509CertImpl is already present
|
||||
* in the cert cache, the cached object is returned. Otherwise,
|
||||
* if it is a X509Certificate, it is first converted to a X509CertImpl.
|
||||
* Then the X509CertImpl is added to the cache and returned.
|
||||
*
|
||||
* Note that all certificates created via generateCertificate(InputStream)
|
||||
* are already interned and this method does not need to be called.
|
||||
* It is useful for certificates that cannot be created via
|
||||
* generateCertificate() and for converting other X509Certificate
|
||||
* implementations to an X509CertImpl.
|
||||
*
|
||||
* @param c The source X509Certificate
|
||||
* @return An X509CertImpl object that is either a cached certificate or a
|
||||
* newly built X509CertImpl from the provided X509Certificate
|
||||
* @throws CertificateException if failures occur while obtaining the DER
|
||||
* encoding for certificate data.
|
||||
*/
|
||||
public static synchronized X509CertImpl intern(X509Certificate c)
|
||||
throws CertificateException {
|
||||
if (c == null) {
|
||||
return null;
|
||||
}
|
||||
boolean isImpl = c instanceof X509CertImpl;
|
||||
byte[] encoding;
|
||||
if (isImpl) {
|
||||
encoding = ((X509CertImpl)c).getEncodedInternal();
|
||||
} else {
|
||||
encoding = c.getEncoded();
|
||||
}
|
||||
X509CertImpl newC = getFromCache(certCache, encoding);
|
||||
if (newC != null) {
|
||||
return newC;
|
||||
}
|
||||
if (isImpl) {
|
||||
newC = (X509CertImpl)c;
|
||||
} else {
|
||||
newC = new X509CertImpl(encoding);
|
||||
encoding = newC.getEncodedInternal();
|
||||
}
|
||||
addToCache(certCache, encoding, newC);
|
||||
return newC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an interned X509CRLImpl for the given certificate.
|
||||
* For more information, see intern(X509Certificate).
|
||||
*
|
||||
* @param c The source X509CRL
|
||||
* @return An X509CRLImpl object that is either a cached CRL or a
|
||||
* newly built X509CRLImpl from the provided X509CRL
|
||||
* @throws CRLException if failures occur while obtaining the DER
|
||||
* encoding for CRL data.
|
||||
*/
|
||||
public static synchronized X509CRLImpl intern(X509CRL c)
|
||||
throws CRLException {
|
||||
if (c == null) {
|
||||
return null;
|
||||
}
|
||||
boolean isImpl = c instanceof X509CRLImpl;
|
||||
byte[] encoding;
|
||||
if (isImpl) {
|
||||
encoding = ((X509CRLImpl)c).getEncodedInternal();
|
||||
} else {
|
||||
encoding = c.getEncoded();
|
||||
}
|
||||
X509CRLImpl newC = getFromCache(crlCache, encoding);
|
||||
if (newC != null) {
|
||||
return newC;
|
||||
}
|
||||
if (isImpl) {
|
||||
newC = (X509CRLImpl)c;
|
||||
} else {
|
||||
newC = new X509CRLImpl(encoding);
|
||||
encoding = newC.getEncodedInternal();
|
||||
}
|
||||
addToCache(crlCache, encoding, newC);
|
||||
return newC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the X509CertImpl or X509CRLImpl from the cache.
|
||||
*/
|
||||
private static synchronized <K,V> V getFromCache(Cache<K,V> cache,
|
||||
byte[] encoding) {
|
||||
Object key = new Cache.EqualByteArray(encoding);
|
||||
return cache.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the X509CertImpl or X509CRLImpl to the cache.
|
||||
*/
|
||||
private static synchronized <V> void addToCache(Cache<Object, V> cache,
|
||||
byte[] encoding, V value) {
|
||||
if (encoding.length > ENC_MAX_LENGTH) {
|
||||
return;
|
||||
}
|
||||
Object key = new Cache.EqualByteArray(encoding);
|
||||
cache.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a <code>CertPath</code> object and initializes it with
|
||||
* the data read from the <code>InputStream</code> inStream. The data
|
||||
* is assumed to be in the default encoding.
|
||||
*
|
||||
* @param inStream an <code>InputStream</code> containing the data
|
||||
* @return a <code>CertPath</code> initialized with the data from the
|
||||
* <code>InputStream</code>
|
||||
* @exception CertificateException if an exception occurs while decoding
|
||||
* @since 1.4
|
||||
*/
|
||||
@Override
|
||||
public CertPath engineGenerateCertPath(InputStream inStream)
|
||||
throws CertificateException
|
||||
{
|
||||
if (inStream == null) {
|
||||
throw new CertificateException("Missing input stream");
|
||||
}
|
||||
try {
|
||||
byte[] encoding = readOneBlock(inStream);
|
||||
if (encoding != null) {
|
||||
return new X509CertPath(new ByteArrayInputStream(encoding));
|
||||
} else {
|
||||
throw new IOException("Empty input");
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new CertificateException(ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a <code>CertPath</code> object and initializes it with
|
||||
* the data read from the <code>InputStream</code> inStream. The data
|
||||
* is assumed to be in the specified encoding.
|
||||
*
|
||||
* @param inStream an <code>InputStream</code> containing the data
|
||||
* @param encoding the encoding used for the data
|
||||
* @return a <code>CertPath</code> initialized with the data from the
|
||||
* <code>InputStream</code>
|
||||
* @exception CertificateException if an exception occurs while decoding or
|
||||
* the encoding requested is not supported
|
||||
* @since 1.4
|
||||
*/
|
||||
@Override
|
||||
public CertPath engineGenerateCertPath(InputStream inStream,
|
||||
String encoding) throws CertificateException
|
||||
{
|
||||
if (inStream == null) {
|
||||
throw new CertificateException("Missing input stream");
|
||||
}
|
||||
try {
|
||||
byte[] data = readOneBlock(inStream);
|
||||
if (data != null) {
|
||||
return new X509CertPath(new ByteArrayInputStream(data), encoding);
|
||||
} else {
|
||||
throw new IOException("Empty input");
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new CertificateException(ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a <code>CertPath</code> object and initializes it with
|
||||
* a <code>List</code> of <code>Certificate</code>s.
|
||||
* <p>
|
||||
* The certificates supplied must be of a type supported by the
|
||||
* <code>CertificateFactory</code>. They will be copied out of the supplied
|
||||
* <code>List</code> object.
|
||||
*
|
||||
* @param certificates a <code>List</code> of <code>Certificate</code>s
|
||||
* @return a <code>CertPath</code> initialized with the supplied list of
|
||||
* certificates
|
||||
* @exception CertificateException if an exception occurs
|
||||
* @since 1.4
|
||||
*/
|
||||
@Override
|
||||
public CertPath
|
||||
engineGenerateCertPath(List<? extends Certificate> certificates)
|
||||
throws CertificateException
|
||||
{
|
||||
return(new X509CertPath(certificates));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iteration of the <code>CertPath</code> encodings supported
|
||||
* by this certificate factory, with the default encoding first.
|
||||
* <p>
|
||||
* Attempts to modify the returned <code>Iterator</code> via its
|
||||
* <code>remove</code> method result in an
|
||||
* <code>UnsupportedOperationException</code>.
|
||||
*
|
||||
* @return an <code>Iterator</code> over the names of the supported
|
||||
* <code>CertPath</code> encodings (as <code>String</code>s)
|
||||
* @since 1.4
|
||||
*/
|
||||
@Override
|
||||
public Iterator<String> engineGetCertPathEncodings() {
|
||||
return(X509CertPath.getEncodingsStatic());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a (possibly empty) collection view of X.509 certificates read
|
||||
* from the given input stream <code>is</code>.
|
||||
*
|
||||
* @param is the input stream with the certificates.
|
||||
*
|
||||
* @return a (possibly empty) collection view of X.509 certificate objects
|
||||
* initialized with the data from the input stream.
|
||||
*
|
||||
* @exception CertificateException on parsing errors.
|
||||
*/
|
||||
@Override
|
||||
public Collection<? extends java.security.cert.Certificate>
|
||||
engineGenerateCertificates(InputStream is)
|
||||
throws CertificateException {
|
||||
if (is == null) {
|
||||
throw new CertificateException("Missing input stream");
|
||||
}
|
||||
try {
|
||||
return parseX509orPKCS7Cert(is);
|
||||
} catch (IOException ioe) {
|
||||
throw new CertificateException(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an X.509 certificate revocation list (CRL) object and
|
||||
* initializes it with the data read from the given input stream
|
||||
* <code>is</code>.
|
||||
*
|
||||
* @param is an input stream with the CRL data.
|
||||
*
|
||||
* @return an X.509 CRL object initialized with the data
|
||||
* from the input stream.
|
||||
*
|
||||
* @exception CRLException on parsing errors.
|
||||
*/
|
||||
@Override
|
||||
public CRL engineGenerateCRL(InputStream is)
|
||||
throws CRLException
|
||||
{
|
||||
if (is == null) {
|
||||
// clear the cache (for debugging)
|
||||
crlCache.clear();
|
||||
throw new CRLException("Missing input stream");
|
||||
}
|
||||
try {
|
||||
byte[] encoding = readOneBlock(is);
|
||||
if (encoding != null) {
|
||||
X509CRLImpl crl = getFromCache(crlCache, encoding);
|
||||
if (crl != null) {
|
||||
return crl;
|
||||
}
|
||||
crl = new X509CRLImpl(encoding);
|
||||
addToCache(crlCache, crl.getEncodedInternal(), crl);
|
||||
return crl;
|
||||
} else {
|
||||
throw new IOException("Empty input");
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new CRLException(ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a (possibly empty) collection view of X.509 CRLs read
|
||||
* from the given input stream <code>is</code>.
|
||||
*
|
||||
* @param is the input stream with the CRLs.
|
||||
*
|
||||
* @return a (possibly empty) collection view of X.509 CRL objects
|
||||
* initialized with the data from the input stream.
|
||||
*
|
||||
* @exception CRLException on parsing errors.
|
||||
*/
|
||||
@Override
|
||||
public Collection<? extends java.security.cert.CRL> engineGenerateCRLs(
|
||||
InputStream is) throws CRLException
|
||||
{
|
||||
if (is == null) {
|
||||
throw new CRLException("Missing input stream");
|
||||
}
|
||||
try {
|
||||
return parseX509orPKCS7CRL(is);
|
||||
} catch (IOException ioe) {
|
||||
throw new CRLException(ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses the data in the given input stream as a sequence of DER
|
||||
* encoded X.509 certificates (in binary or base 64 encoded format) OR
|
||||
* as a single PKCS#7 encoded blob (in binary or base64 encoded format).
|
||||
*/
|
||||
private Collection<? extends java.security.cert.Certificate>
|
||||
parseX509orPKCS7Cert(InputStream is)
|
||||
throws CertificateException, IOException
|
||||
{
|
||||
int peekByte;
|
||||
byte[] data;
|
||||
PushbackInputStream pbis = new PushbackInputStream(is);
|
||||
Collection<X509CertImpl> coll = new ArrayList<>();
|
||||
|
||||
// Test the InputStream for end-of-stream. If the stream's
|
||||
// initial state is already at end-of-stream then return
|
||||
// an empty collection. Otherwise, push the byte back into the
|
||||
// stream and let readOneBlock look for the first certificate.
|
||||
peekByte = pbis.read();
|
||||
if (peekByte == -1) {
|
||||
return new ArrayList<>(0);
|
||||
} else {
|
||||
pbis.unread(peekByte);
|
||||
data = readOneBlock(pbis);
|
||||
}
|
||||
|
||||
// If we end up with a null value after reading the first block
|
||||
// then we know the end-of-stream has been reached and no certificate
|
||||
// data has been found.
|
||||
if (data == null) {
|
||||
throw new CertificateException("No certificate data found");
|
||||
}
|
||||
|
||||
try {
|
||||
PKCS7 pkcs7 = new PKCS7(data);
|
||||
X509Certificate[] certs = pkcs7.getCertificates();
|
||||
// certs are optional in PKCS #7
|
||||
if (certs != null) {
|
||||
return Arrays.asList(certs);
|
||||
} else {
|
||||
// no certificates provided
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
} catch (ParsingException e) {
|
||||
while (data != null) {
|
||||
coll.add(new X509CertImpl(data));
|
||||
data = readOneBlock(pbis);
|
||||
}
|
||||
}
|
||||
return coll;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses the data in the given input stream as a sequence of DER encoded
|
||||
* X.509 CRLs (in binary or base 64 encoded format) OR as a single PKCS#7
|
||||
* encoded blob (in binary or base 64 encoded format).
|
||||
*/
|
||||
private Collection<? extends java.security.cert.CRL>
|
||||
parseX509orPKCS7CRL(InputStream is)
|
||||
throws CRLException, IOException
|
||||
{
|
||||
int peekByte;
|
||||
byte[] data;
|
||||
PushbackInputStream pbis = new PushbackInputStream(is);
|
||||
Collection<X509CRLImpl> coll = new ArrayList<>();
|
||||
|
||||
// Test the InputStream for end-of-stream. If the stream's
|
||||
// initial state is already at end-of-stream then return
|
||||
// an empty collection. Otherwise, push the byte back into the
|
||||
// stream and let readOneBlock look for the first CRL.
|
||||
peekByte = pbis.read();
|
||||
if (peekByte == -1) {
|
||||
return new ArrayList<>(0);
|
||||
} else {
|
||||
pbis.unread(peekByte);
|
||||
data = readOneBlock(pbis);
|
||||
}
|
||||
|
||||
// If we end up with a null value after reading the first block
|
||||
// then we know the end-of-stream has been reached and no CRL
|
||||
// data has been found.
|
||||
if (data == null) {
|
||||
throw new CRLException("No CRL data found");
|
||||
}
|
||||
|
||||
try {
|
||||
PKCS7 pkcs7 = new PKCS7(data);
|
||||
X509CRL[] crls = pkcs7.getCRLs();
|
||||
// CRLs are optional in PKCS #7
|
||||
if (crls != null) {
|
||||
return Arrays.asList(crls);
|
||||
} else {
|
||||
// no crls provided
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
} catch (ParsingException e) {
|
||||
while (data != null) {
|
||||
coll.add(new X509CRLImpl(data));
|
||||
data = readOneBlock(pbis);
|
||||
}
|
||||
}
|
||||
return coll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ASN.1 SEQUENCE from a stream, which might be a BER-encoded
|
||||
* binary block or a PEM-style BASE64-encoded ASCII data. In the latter
|
||||
* case, it's de-BASE64'ed before return.
|
||||
*
|
||||
* After the reading, the input stream pointer is after the BER block, or
|
||||
* after the newline character after the -----END SOMETHING----- line.
|
||||
*
|
||||
* @param is the InputStream
|
||||
* @returns byte block or null if end of stream
|
||||
* @throws IOException If any parsing error
|
||||
*/
|
||||
private static byte[] readOneBlock(InputStream is) throws IOException {
|
||||
|
||||
// The first character of a BLOCK.
|
||||
int c = is.read();
|
||||
if (c == -1) {
|
||||
return null;
|
||||
}
|
||||
if (c == DerValue.tag_Sequence) {
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream(2048);
|
||||
bout.write(c);
|
||||
readBERInternal(is, bout, c);
|
||||
return bout.toByteArray();
|
||||
} else {
|
||||
// Read BASE64 encoded data, might skip info at the beginning
|
||||
char[] data = new char[2048];
|
||||
int pos = 0;
|
||||
|
||||
// Step 1: Read until header is found
|
||||
int hyphen = (c=='-') ? 1: 0; // count of consequent hyphens
|
||||
int last = (c=='-') ? -1: c; // the char before hyphen
|
||||
while (true) {
|
||||
int next = is.read();
|
||||
if (next == -1) {
|
||||
// We accept useless data after the last block,
|
||||
// say, empty lines.
|
||||
return null;
|
||||
}
|
||||
if (next == '-') {
|
||||
hyphen++;
|
||||
} else {
|
||||
hyphen = 0;
|
||||
last = next;
|
||||
}
|
||||
if (hyphen == 5 && (last == -1 || last == '\r' || last == '\n')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: Read the rest of header, determine the line end
|
||||
int end;
|
||||
StringBuilder header = new StringBuilder("-----");
|
||||
while (true) {
|
||||
int next = is.read();
|
||||
if (next == -1) {
|
||||
throw new IOException("Incomplete data");
|
||||
}
|
||||
if (next == '\n') {
|
||||
end = '\n';
|
||||
break;
|
||||
}
|
||||
if (next == '\r') {
|
||||
next = is.read();
|
||||
if (next == -1) {
|
||||
throw new IOException("Incomplete data");
|
||||
}
|
||||
if (next == '\n') {
|
||||
end = '\n';
|
||||
} else {
|
||||
end = '\r';
|
||||
data[pos++] = (char)next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
header.append((char)next);
|
||||
}
|
||||
|
||||
// Step 3: Read the data
|
||||
while (true) {
|
||||
int next = is.read();
|
||||
if (next == -1) {
|
||||
throw new IOException("Incomplete data");
|
||||
}
|
||||
if (next != '-') {
|
||||
data[pos++] = (char)next;
|
||||
if (pos >= data.length) {
|
||||
data = Arrays.copyOf(data, data.length+1024);
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4: Consume the footer
|
||||
StringBuilder footer = new StringBuilder("-");
|
||||
while (true) {
|
||||
int next = is.read();
|
||||
// Add next == '\n' for maximum safety, in case endline
|
||||
// is not consistent.
|
||||
if (next == -1 || next == end || next == '\n') {
|
||||
break;
|
||||
}
|
||||
if (next != '\r') footer.append((char)next);
|
||||
}
|
||||
|
||||
checkHeaderFooter(header.toString(), footer.toString());
|
||||
|
||||
return Pem.decode(new String(data, 0, pos));
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkHeaderFooter(String header,
|
||||
String footer) throws IOException {
|
||||
if (header.length() < 16 || !header.startsWith("-----BEGIN ") ||
|
||||
!header.endsWith("-----")) {
|
||||
throw new IOException("Illegal header: " + header);
|
||||
}
|
||||
if (footer.length() < 14 || !footer.startsWith("-----END ") ||
|
||||
!footer.endsWith("-----")) {
|
||||
throw new IOException("Illegal footer: " + footer);
|
||||
}
|
||||
String headerType = header.substring(11, header.length()-5);
|
||||
String footerType = footer.substring(9, footer.length()-5);
|
||||
if (!headerType.equals(footerType)) {
|
||||
throw new IOException("Header and footer do not match: " +
|
||||
header + " " + footer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read one BER data block. This method is aware of indefinite-length BER
|
||||
* encoding and will read all of the sub-sections in a recursive way
|
||||
*
|
||||
* @param is Read from this InputStream
|
||||
* @param bout Write into this OutputStream
|
||||
* @param tag Tag already read (-1 mean not read)
|
||||
* @returns The current tag, used to check EOC in indefinite-length BER
|
||||
* @throws IOException Any parsing error
|
||||
*/
|
||||
private static int readBERInternal(InputStream is,
|
||||
ByteArrayOutputStream bout, int tag) throws IOException {
|
||||
|
||||
if (tag == -1) { // Not read before the call, read now
|
||||
tag = is.read();
|
||||
if (tag == -1) {
|
||||
throw new IOException("BER/DER tag info absent");
|
||||
}
|
||||
if ((tag & 0x1f) == 0x1f) {
|
||||
throw new IOException("Multi octets tag not supported");
|
||||
}
|
||||
bout.write(tag);
|
||||
}
|
||||
|
||||
int n = is.read();
|
||||
if (n == -1) {
|
||||
throw new IOException("BER/DER length info absent");
|
||||
}
|
||||
bout.write(n);
|
||||
|
||||
int length;
|
||||
|
||||
if (n == 0x80) { // Indefinite-length encoding
|
||||
if ((tag & 0x20) != 0x20) {
|
||||
throw new IOException(
|
||||
"Non constructed encoding must have definite length");
|
||||
}
|
||||
while (true) {
|
||||
int subTag = readBERInternal(is, bout, -1);
|
||||
if (subTag == 0) { // EOC, end of indefinite-length section
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (n < 0x80) {
|
||||
length = n;
|
||||
} else if (n == 0x81) {
|
||||
length = is.read();
|
||||
if (length == -1) {
|
||||
throw new IOException("Incomplete BER/DER length info");
|
||||
}
|
||||
bout.write(length);
|
||||
} else if (n == 0x82) {
|
||||
int highByte = is.read();
|
||||
int lowByte = is.read();
|
||||
if (lowByte == -1) {
|
||||
throw new IOException("Incomplete BER/DER length info");
|
||||
}
|
||||
bout.write(highByte);
|
||||
bout.write(lowByte);
|
||||
length = (highByte << 8) | lowByte;
|
||||
} else if (n == 0x83) {
|
||||
int highByte = is.read();
|
||||
int midByte = is.read();
|
||||
int lowByte = is.read();
|
||||
if (lowByte == -1) {
|
||||
throw new IOException("Incomplete BER/DER length info");
|
||||
}
|
||||
bout.write(highByte);
|
||||
bout.write(midByte);
|
||||
bout.write(lowByte);
|
||||
length = (highByte << 16) | (midByte << 8) | lowByte;
|
||||
} else if (n == 0x84) {
|
||||
int highByte = is.read();
|
||||
int nextByte = is.read();
|
||||
int midByte = is.read();
|
||||
int lowByte = is.read();
|
||||
if (lowByte == -1) {
|
||||
throw new IOException("Incomplete BER/DER length info");
|
||||
}
|
||||
if (highByte > 127) {
|
||||
throw new IOException("Invalid BER/DER data (a little huge?)");
|
||||
}
|
||||
bout.write(highByte);
|
||||
bout.write(nextByte);
|
||||
bout.write(midByte);
|
||||
bout.write(lowByte);
|
||||
length = (highByte << 24 ) | (nextByte << 16) |
|
||||
(midByte << 8) | lowByte;
|
||||
} else { // ignore longer length forms
|
||||
throw new IOException("Invalid BER/DER data (too huge?)");
|
||||
}
|
||||
if (readFully(is, bout, length) != length) {
|
||||
throw new IOException("Incomplete BER/DER data");
|
||||
}
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.cert.X509CertSelector;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.util.DerInputStream;
|
||||
import sun.security.x509.SerialNumber;
|
||||
import sun.security.x509.AuthorityKeyIdentifierExtension;
|
||||
|
||||
/**
|
||||
* An adaptable X509 certificate selector for forward certification path
|
||||
* building. This selector overrides the default X509CertSelector matching
|
||||
* rules for the subjectKeyIdentifier and serialNumber criteria, and adds
|
||||
* additional rules for certificate validity.
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
class AdaptableX509CertSelector extends X509CertSelector {
|
||||
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
|
||||
// The start date of a validity period.
|
||||
private Date startDate;
|
||||
|
||||
// The end date of a validity period.
|
||||
private Date endDate;
|
||||
|
||||
// The subject key identifier
|
||||
private byte[] ski;
|
||||
|
||||
// The serial number
|
||||
private BigInteger serial;
|
||||
|
||||
/**
|
||||
* Sets the criterion of the X509Certificate validity period.
|
||||
*
|
||||
* Normally, we may not have to check that a certificate validity period
|
||||
* must fall within its issuer's certificate validity period. However,
|
||||
* when we face root CA key updates for version 1 certificates, according
|
||||
* to scheme of RFC 4210 or 2510, the validity periods should be checked
|
||||
* to determine the right issuer's certificate.
|
||||
*
|
||||
* Conservatively, we will only check the validity periods for version
|
||||
* 1 and version 2 certificates. For version 3 certificates, we can
|
||||
* determine the right issuer by authority and subject key identifier
|
||||
* extensions.
|
||||
*
|
||||
* @param startDate the start date of a validity period that must fall
|
||||
* within the certificate validity period for the X509Certificate
|
||||
* @param endDate the end date of a validity period that must fall
|
||||
* within the certificate validity period for the X509Certificate
|
||||
*/
|
||||
void setValidityPeriod(Date startDate, Date endDate) {
|
||||
this.startDate = startDate;
|
||||
this.endDate = endDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* This selector overrides the subjectKeyIdentifier matching rules of
|
||||
* X509CertSelector, so it throws IllegalArgumentException if this method
|
||||
* is ever called.
|
||||
*/
|
||||
@Override
|
||||
public void setSubjectKeyIdentifier(byte[] subjectKeyID) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
/**
|
||||
* This selector overrides the serialNumber matching rules of
|
||||
* X509CertSelector, so it throws IllegalArgumentException if this method
|
||||
* is ever called.
|
||||
*/
|
||||
@Override
|
||||
public void setSerialNumber(BigInteger serial) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the subjectKeyIdentifier and serialNumber criteria from the
|
||||
* authority key identifier extension.
|
||||
*
|
||||
* The subjectKeyIdentifier criterion is set to the keyIdentifier field
|
||||
* of the extension, or null if it is empty. The serialNumber criterion
|
||||
* is set to the authorityCertSerialNumber field, or null if it is empty.
|
||||
*
|
||||
* Note that we do not set the subject criterion to the
|
||||
* authorityCertIssuer field of the extension. The caller MUST set
|
||||
* the subject criterion before calling match().
|
||||
*
|
||||
* @param ext the authorityKeyIdentifier extension
|
||||
* @throws IOException if there is an error parsing the extension
|
||||
*/
|
||||
void setSkiAndSerialNumber(AuthorityKeyIdentifierExtension ext)
|
||||
throws IOException {
|
||||
|
||||
ski = null;
|
||||
serial = null;
|
||||
|
||||
if (ext != null) {
|
||||
ski = ext.getEncodedKeyIdentifier();
|
||||
SerialNumber asn = (SerialNumber)ext.get(
|
||||
AuthorityKeyIdentifierExtension.SERIAL_NUMBER);
|
||||
if (asn != null) {
|
||||
serial = asn.getNumber();
|
||||
}
|
||||
// the subject criterion should be set by the caller
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decides whether a <code>Certificate</code> should be selected.
|
||||
*
|
||||
* This method overrides the matching rules for the subjectKeyIdentifier
|
||||
* and serialNumber criteria and adds additional rules for certificate
|
||||
* validity.
|
||||
*
|
||||
* For the purpose of compatibility, when a certificate is of
|
||||
* version 1 and version 2, or the certificate does not include
|
||||
* a subject key identifier extension, the selection criterion
|
||||
* of subjectKeyIdentifier will be disabled.
|
||||
*/
|
||||
@Override
|
||||
public boolean match(Certificate cert) {
|
||||
X509Certificate xcert = (X509Certificate)cert;
|
||||
|
||||
// match subject key identifier
|
||||
if (!matchSubjectKeyID(xcert)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// In practice, a CA may replace its root certificate and require that
|
||||
// the existing certificate is still valid, even if the AKID extension
|
||||
// does not match the replacement root certificate fields.
|
||||
//
|
||||
// Conservatively, we only support the replacement for version 1 and
|
||||
// version 2 certificate. As for version 3, the certificate extension
|
||||
// may contain sensitive information (for example, policies), the
|
||||
// AKID need to be respected to seek the exact certificate in case
|
||||
// of key or certificate abuse.
|
||||
int version = xcert.getVersion();
|
||||
if (serial != null && version > 2) {
|
||||
if (!serial.equals(xcert.getSerialNumber())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the validity period for version 1 and 2 certificate.
|
||||
if (version < 3) {
|
||||
if (startDate != null) {
|
||||
try {
|
||||
xcert.checkValidity(startDate);
|
||||
} catch (CertificateException ce) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (endDate != null) {
|
||||
try {
|
||||
xcert.checkValidity(endDate);
|
||||
} catch (CertificateException ce) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!super.match(cert)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Match on subject key identifier extension value. These matching rules
|
||||
* are identical to X509CertSelector except that if the certificate does
|
||||
* not have a subject key identifier extension, it returns true.
|
||||
*/
|
||||
private boolean matchSubjectKeyID(X509Certificate xcert) {
|
||||
if (ski == null) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
byte[] extVal = xcert.getExtensionValue("2.5.29.14");
|
||||
if (extVal == null) {
|
||||
if (debug != null) {
|
||||
debug.println("AdaptableX509CertSelector.match: "
|
||||
+ "no subject key ID extension. Subject: "
|
||||
+ xcert.getSubjectX500Principal());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
DerInputStream in = new DerInputStream(extVal);
|
||||
byte[] certSubjectKeyID = in.getOctetString();
|
||||
if (certSubjectKeyID == null ||
|
||||
!Arrays.equals(ski, certSubjectKeyID)) {
|
||||
if (debug != null) {
|
||||
debug.println("AdaptableX509CertSelector.match: "
|
||||
+ "subject key IDs don't match. "
|
||||
+ "Expected: " + Arrays.toString(ski) + " "
|
||||
+ "Cert's: " + Arrays.toString(certSubjectKeyID));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
if (debug != null) {
|
||||
debug.println("AdaptableX509CertSelector.match: "
|
||||
+ "exception in subject key ID check");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
AdaptableX509CertSelector copy =
|
||||
(AdaptableX509CertSelector)super.clone();
|
||||
if (startDate != null) {
|
||||
copy.startDate = (Date)startDate.clone();
|
||||
}
|
||||
|
||||
if (endDate != null) {
|
||||
copy.endDate = (Date)endDate.clone();
|
||||
}
|
||||
|
||||
if (ski != null) {
|
||||
copy.ski = ski.clone();
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
265
jdkSrc/jdk8/sun/security/provider/certpath/AdjacencyList.java
Normal file
265
jdkSrc/jdk8/sun/security/provider/certpath/AdjacencyList.java
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An AdjacencyList is used to store the history of certification paths
|
||||
* attempted in constructing a path from an initiator to a target. The
|
||||
* AdjacencyList is initialized with a <code>List</code> of
|
||||
* <code>List</code>s, where each sub-<code>List</code> contains objects of
|
||||
* type <code>Vertex</code>. A <code>Vertex</code> describes one possible or
|
||||
* actual step in the chain building process, and the associated
|
||||
* <code>Certificate</code>. Specifically, a <code>Vertex</code> object
|
||||
* contains a <code>Certificate</code> and an index value referencing the
|
||||
* next sub-list in the process. If the index value is -1 then this
|
||||
* <code>Vertex</code> doesn't continue the attempted build path.
|
||||
* <p>
|
||||
* Example:
|
||||
* <p>
|
||||
* Attempted Paths:<ul>
|
||||
* <li>C1->C2->C3
|
||||
* <li>C1->C4->C5
|
||||
* <li>C1->C4->C6
|
||||
* <li>C1->C4->C7
|
||||
* <li>C1->C8->C9
|
||||
* <li>C1->C10->C11
|
||||
* </ul>
|
||||
* <p>
|
||||
* AdjacencyList structure:<ul>
|
||||
* <li>AL[0] = C1,1
|
||||
* <li>AL[1] = C2,2 =>C4,3 =>C8,4 =>C10,5
|
||||
* <li>AL[2] = C3,-1
|
||||
* <li>AL[3] = C5,-1 =>C6,-1 =>C7,-1
|
||||
* <li>AL[4] = C9,-1
|
||||
* <li>AL[5] = C11,-1
|
||||
* </ul>
|
||||
* <p>
|
||||
* The iterator method returns objects of type <code>BuildStep</code>, not
|
||||
* objects of type <code>Vertex</code>.
|
||||
* A <code>BuildStep</code> contains a <code>Vertex</code> and a result code,
|
||||
* accessible via getResult method. There are five result values.
|
||||
* <code>POSSIBLE</code> denotes that the current step represents a
|
||||
* <code>Certificate</code> that the builder is considering at this point in
|
||||
* the build. <code>FOLLOW</code> denotes a <code>Certificate</code> (one of
|
||||
* those noted as <code>POSSIBLE</code>) that the builder is using to try
|
||||
* extending the chain. <code>BACK</code> represents that a
|
||||
* <code>FOLLOW</code> was incorrect, and is being removed from the chain.
|
||||
* There is exactly one <code>FOLLOW</code> for each <code>BACK</code>. The
|
||||
* values <code>SUCCEED</code> and <code>FAIL</code> mean that we've come to
|
||||
* the end of the build process, and there will not be any more entries in
|
||||
* the list.
|
||||
* <p>
|
||||
* @see sun.security.provider.certpath.BuildStep
|
||||
* @see sun.security.provider.certpath.Vertex
|
||||
* <p>
|
||||
* @author seth proctor
|
||||
* @since 1.4
|
||||
*/
|
||||
public class AdjacencyList {
|
||||
|
||||
// the actual set of steps the AdjacencyList represents
|
||||
private ArrayList<BuildStep> mStepList;
|
||||
|
||||
// the original list
|
||||
private List<List<Vertex>> mOrigList;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>AdjacencyList</code> based on the specified
|
||||
* <code>List</code>. See the example above.
|
||||
*
|
||||
* @param list a <code>List</code> of <code>List</code>s of
|
||||
* <code>Vertex</code> objects
|
||||
*/
|
||||
public AdjacencyList(List<List<Vertex>> list) {
|
||||
mStepList = new ArrayList<BuildStep>();
|
||||
mOrigList = list;
|
||||
buildList(list, 0, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an <code>Iterator</code> to iterate over the set of
|
||||
* <code>BuildStep</code>s in build-order. Any attempts to change
|
||||
* the list through the remove method will fail.
|
||||
*
|
||||
* @return an <code>Iterator</code> over the <code>BuildStep</code>s
|
||||
*/
|
||||
public Iterator<BuildStep> iterator() {
|
||||
return Collections.unmodifiableList(mStepList).iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of attempted paths (useful for debugging).
|
||||
*/
|
||||
public int numAttemptedPaths() {
|
||||
return mOrigList.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive, private method which actually builds the step list from
|
||||
* the given adjacency list. <code>Follow</code> is the parent BuildStep
|
||||
* that we followed to get here, and if it's null, it means that we're
|
||||
* at the start.
|
||||
*/
|
||||
private boolean buildList(List<List<Vertex>> theList, int index,
|
||||
BuildStep follow) {
|
||||
|
||||
// Each time this method is called, we're examining a new list
|
||||
// from the global list. So, we have to start by getting the list
|
||||
// that contains the set of Vertexes we're considering.
|
||||
List<Vertex> l = theList.get(index);
|
||||
|
||||
// we're interested in the case where all indexes are -1...
|
||||
boolean allNegOne = true;
|
||||
// ...and in the case where every entry has a Throwable
|
||||
boolean allXcps = true;
|
||||
|
||||
for (Vertex v : l) {
|
||||
if (v.getIndex() != -1) {
|
||||
// count an empty list the same as an index of -1...this
|
||||
// is to patch a bug somewhere in the builder
|
||||
if (theList.get(v.getIndex()).size() != 0)
|
||||
allNegOne = false;
|
||||
} else {
|
||||
if (v.getThrowable() == null)
|
||||
allXcps = false;
|
||||
}
|
||||
// every entry, regardless of the final use for it, is always
|
||||
// entered as a possible step before we take any actions
|
||||
mStepList.add(new BuildStep(v, BuildStep.POSSIBLE));
|
||||
}
|
||||
|
||||
if (allNegOne) {
|
||||
// There are two cases that we could be looking at here. We
|
||||
// may need to back up, or the build may have succeeded at
|
||||
// this point. This is based on whether or not any
|
||||
// exceptions were found in the list.
|
||||
if (allXcps) {
|
||||
// we need to go back...see if this is the last one
|
||||
if (follow == null)
|
||||
mStepList.add(new BuildStep(null, BuildStep.FAIL));
|
||||
else
|
||||
mStepList.add(new BuildStep(follow.getVertex(),
|
||||
BuildStep.BACK));
|
||||
|
||||
return false;
|
||||
} else {
|
||||
// we succeeded...now the only question is which is the
|
||||
// successful step? If there's only one entry without
|
||||
// a throwable, then that's the successful step. Otherwise,
|
||||
// we'll have to make some guesses...
|
||||
List<Vertex> possibles = new ArrayList<>();
|
||||
for (Vertex v : l) {
|
||||
if (v.getThrowable() == null)
|
||||
possibles.add(v);
|
||||
}
|
||||
|
||||
if (possibles.size() == 1) {
|
||||
// real easy...we've found the final Vertex
|
||||
mStepList.add(new BuildStep(possibles.get(0),
|
||||
BuildStep.SUCCEED));
|
||||
} else {
|
||||
// ok...at this point, there is more than one Cert
|
||||
// which might be the succeed step...how do we know
|
||||
// which it is? I'm going to assume that our builder
|
||||
// algorithm is good enough to know which is the
|
||||
// correct one, and put it first...but a FIXME goes
|
||||
// here anyway, and we should be comparing to the
|
||||
// target/initiator Cert...
|
||||
mStepList.add(new BuildStep(possibles.get(0),
|
||||
BuildStep.SUCCEED));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// There's at least one thing that we can try before we give
|
||||
// up and go back. Run through the list now, and enter a new
|
||||
// BuildStep for each path that we try to follow. If none of
|
||||
// the paths we try produce a successful end, we're going to
|
||||
// have to back out ourselves.
|
||||
boolean success = false;
|
||||
|
||||
for (Vertex v : l) {
|
||||
|
||||
// Note that we'll only find a SUCCEED case when we're
|
||||
// looking at the last possible path, so we don't need to
|
||||
// consider success in the while loop
|
||||
|
||||
if (v.getIndex() != -1) {
|
||||
if (theList.get(v.getIndex()).size() != 0) {
|
||||
// If the entry we're looking at doesn't have an
|
||||
// index of -1, and doesn't lead to an empty list,
|
||||
// then it's something we follow!
|
||||
BuildStep bs = new BuildStep(v, BuildStep.FOLLOW);
|
||||
mStepList.add(bs);
|
||||
success = buildList(theList, v.getIndex(), bs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
// We're already finished!
|
||||
return true;
|
||||
} else {
|
||||
// We failed, and we've exhausted all the paths that we
|
||||
// could take. The only choice is to back ourselves out.
|
||||
if (follow == null)
|
||||
mStepList.add(new BuildStep(null, BuildStep.FAIL));
|
||||
else
|
||||
mStepList.add(new BuildStep(follow.getVertex(),
|
||||
BuildStep.BACK));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints out a string representation of this AdjacencyList.
|
||||
*
|
||||
* @return String representation
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("[\n");
|
||||
|
||||
int i = 0;
|
||||
for (List<Vertex> l : mOrigList) {
|
||||
sb.append("LinkedList[").append(i++).append("]:\n");
|
||||
|
||||
for (Vertex step : l) {
|
||||
sb.append(step.toString()).append("\n");
|
||||
}
|
||||
}
|
||||
sb.append("]\n");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
395
jdkSrc/jdk8/sun/security/provider/certpath/AlgorithmChecker.java
Normal file
395
jdkSrc/jdk8/sun/security/provider/certpath/AlgorithmChecker.java
Normal file
@@ -0,0 +1,395 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.security.AlgorithmConstraints;
|
||||
import java.security.CryptoPrimitive;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
import java.util.EnumSet;
|
||||
import java.math.BigInteger;
|
||||
import java.security.PublicKey;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.cert.PKIXCertPathChecker;
|
||||
import java.security.cert.TrustAnchor;
|
||||
import java.security.cert.CRLException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertPathValidatorException;
|
||||
import java.security.cert.CertPathValidatorException.BasicReason;
|
||||
import java.security.cert.PKIXReason;
|
||||
import java.security.interfaces.DSAParams;
|
||||
import java.security.interfaces.DSAPublicKey;
|
||||
import java.security.spec.DSAPublicKeySpec;
|
||||
|
||||
import sun.security.util.ConstraintsParameters;
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.util.DisabledAlgorithmConstraints;
|
||||
import sun.security.validator.Validator;
|
||||
import sun.security.x509.AlgorithmId;
|
||||
import sun.security.x509.X509CertImpl;
|
||||
|
||||
/**
|
||||
* A {@code PKIXCertPathChecker} implementation to check whether a
|
||||
* specified certificate contains the required algorithm constraints.
|
||||
* <p>
|
||||
* Certificate fields such as the subject public key, the signature
|
||||
* algorithm, key usage, extended key usage, etc. need to conform to
|
||||
* the specified algorithm constraints.
|
||||
*
|
||||
* @see PKIXCertPathChecker
|
||||
* @see PKIXParameters
|
||||
*/
|
||||
public final class AlgorithmChecker extends PKIXCertPathChecker {
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
|
||||
private final AlgorithmConstraints constraints;
|
||||
private final PublicKey trustedPubKey;
|
||||
private final Date date;
|
||||
private PublicKey prevPubKey;
|
||||
private final String variant;
|
||||
private TrustAnchor anchor;
|
||||
|
||||
private static final Set<CryptoPrimitive> SIGNATURE_PRIMITIVE_SET =
|
||||
Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
|
||||
|
||||
private static final Set<CryptoPrimitive> KU_PRIMITIVE_SET =
|
||||
Collections.unmodifiableSet(EnumSet.of(
|
||||
CryptoPrimitive.SIGNATURE,
|
||||
CryptoPrimitive.KEY_ENCAPSULATION,
|
||||
CryptoPrimitive.PUBLIC_KEY_ENCRYPTION,
|
||||
CryptoPrimitive.KEY_AGREEMENT));
|
||||
|
||||
private static final DisabledAlgorithmConstraints
|
||||
certPathDefaultConstraints =
|
||||
DisabledAlgorithmConstraints.certPathConstraints();
|
||||
|
||||
/**
|
||||
* Create a new {@code AlgorithmChecker} with the given
|
||||
* {@code TrustAnchor} and {@code String} variant.
|
||||
*
|
||||
* @param anchor the trust anchor selected to validate the target
|
||||
* certificate
|
||||
* @param variant the Validator variant of the operation. A null value
|
||||
* passed will set it to Validator.GENERIC.
|
||||
*/
|
||||
public AlgorithmChecker(TrustAnchor anchor, String variant) {
|
||||
this(anchor, certPathDefaultConstraints, null, variant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code AlgorithmChecker} with the given
|
||||
* {@code AlgorithmConstraints} and {@code String} variant.
|
||||
*
|
||||
* Note that this constructor can initialize a variation of situations where
|
||||
* the AlgorithmConstraints or Variant maybe known.
|
||||
*
|
||||
* @param constraints the algorithm constraints (or null)
|
||||
* @param variant the Validator variant of the operation. A null value
|
||||
* passed will set it to Validator.GENERIC.
|
||||
*/
|
||||
public AlgorithmChecker(AlgorithmConstraints constraints, String variant) {
|
||||
this(null, constraints, null, variant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code AlgorithmChecker} with the
|
||||
* given {@code TrustAnchor}, {@code AlgorithmConstraints}, {@code Date},
|
||||
* and {@code String} variant.
|
||||
*
|
||||
* @param anchor the trust anchor selected to validate the target
|
||||
* certificate
|
||||
* @param constraints the algorithm constraints (or null)
|
||||
* @param date the date specified by the PKIXParameters date, or the
|
||||
* timestamp if JAR files are being validated and the
|
||||
* JAR is timestamped. May be null if no timestamp or
|
||||
* PKIXParameter date is set.
|
||||
* @param variant the Validator variant of the operation. A null value
|
||||
* passed will set it to Validator.GENERIC.
|
||||
*/
|
||||
public AlgorithmChecker(TrustAnchor anchor,
|
||||
AlgorithmConstraints constraints, Date date, String variant) {
|
||||
|
||||
if (anchor != null) {
|
||||
if (anchor.getTrustedCert() != null) {
|
||||
this.trustedPubKey = anchor.getTrustedCert().getPublicKey();
|
||||
} else {
|
||||
this.trustedPubKey = anchor.getCAPublicKey();
|
||||
}
|
||||
this.anchor = anchor;
|
||||
} else {
|
||||
this.trustedPubKey = null;
|
||||
}
|
||||
|
||||
this.prevPubKey = this.trustedPubKey;
|
||||
this.constraints = (constraints == null ? certPathDefaultConstraints :
|
||||
constraints);
|
||||
this.date = date;
|
||||
this.variant = (variant == null ? Validator.VAR_GENERIC : variant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code AlgorithmChecker} with the given {@code TrustAnchor},
|
||||
* {@code PKIXParameter} date, and {@code variant}.
|
||||
*
|
||||
* @param anchor the trust anchor selected to validate the target
|
||||
* certificate
|
||||
* @param date the date specified by the PKIXParameters date, or the
|
||||
* timestamp if JAR files are being validated and the
|
||||
* JAR is timestamped. May be null if no timestamp or
|
||||
* PKIXParameter date is set.
|
||||
* @param variant the Validator variant of the operation. A null value
|
||||
* passed will set it to Validator.GENERIC.
|
||||
*/
|
||||
public AlgorithmChecker(TrustAnchor anchor, Date date, String variant) {
|
||||
this(anchor, certPathDefaultConstraints, date, variant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(boolean forward) throws CertPathValidatorException {
|
||||
// Note that this class does not support forward mode.
|
||||
if (!forward) {
|
||||
if (trustedPubKey != null) {
|
||||
prevPubKey = trustedPubKey;
|
||||
} else {
|
||||
prevPubKey = null;
|
||||
}
|
||||
} else {
|
||||
throw new
|
||||
CertPathValidatorException("forward checking not supported");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForwardCheckingSupported() {
|
||||
// Note that as this class does not support forward mode, the method
|
||||
// will always returns false.
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedExtensions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void check(Certificate cert,
|
||||
Collection<String> unresolvedCritExts)
|
||||
throws CertPathValidatorException {
|
||||
|
||||
if (!(cert instanceof X509Certificate) || constraints == null) {
|
||||
// ignore the check for non-x.509 certificate or null constraints
|
||||
return;
|
||||
}
|
||||
|
||||
// check the key usage and key size
|
||||
boolean[] keyUsage = ((X509Certificate) cert).getKeyUsage();
|
||||
if (keyUsage != null && keyUsage.length < 9) {
|
||||
throw new CertPathValidatorException(
|
||||
"incorrect KeyUsage extension",
|
||||
null, null, -1, PKIXReason.INVALID_KEY_USAGE);
|
||||
}
|
||||
|
||||
X509CertImpl x509Cert;
|
||||
AlgorithmId algorithmId;
|
||||
try {
|
||||
x509Cert = X509CertImpl.toImpl((X509Certificate)cert);
|
||||
algorithmId = (AlgorithmId)x509Cert.get(X509CertImpl.SIG_ALG);
|
||||
} catch (CertificateException ce) {
|
||||
throw new CertPathValidatorException(ce);
|
||||
}
|
||||
|
||||
AlgorithmParameters currSigAlgParams = algorithmId.getParameters();
|
||||
PublicKey currPubKey = cert.getPublicKey();
|
||||
String currSigAlg = x509Cert.getSigAlgName();
|
||||
|
||||
// Check the signature algorithm and parameters against constraints.
|
||||
if (!constraints.permits(SIGNATURE_PRIMITIVE_SET, currSigAlg,
|
||||
currSigAlgParams)) {
|
||||
throw new CertPathValidatorException(
|
||||
"Algorithm constraints check failed on signature " +
|
||||
"algorithm: " + currSigAlg, null, null, -1,
|
||||
BasicReason.ALGORITHM_CONSTRAINED);
|
||||
}
|
||||
|
||||
// Assume all key usage bits are set if key usage is not present
|
||||
Set<CryptoPrimitive> primitives = KU_PRIMITIVE_SET;
|
||||
|
||||
if (keyUsage != null) {
|
||||
primitives = EnumSet.noneOf(CryptoPrimitive.class);
|
||||
|
||||
if (keyUsage[0] || keyUsage[1] || keyUsage[5] || keyUsage[6]) {
|
||||
// keyUsage[0]: KeyUsage.digitalSignature
|
||||
// keyUsage[1]: KeyUsage.nonRepudiation
|
||||
// keyUsage[5]: KeyUsage.keyCertSign
|
||||
// keyUsage[6]: KeyUsage.cRLSign
|
||||
primitives.add(CryptoPrimitive.SIGNATURE);
|
||||
}
|
||||
|
||||
if (keyUsage[2]) { // KeyUsage.keyEncipherment
|
||||
primitives.add(CryptoPrimitive.KEY_ENCAPSULATION);
|
||||
}
|
||||
|
||||
if (keyUsage[3]) { // KeyUsage.dataEncipherment
|
||||
primitives.add(CryptoPrimitive.PUBLIC_KEY_ENCRYPTION);
|
||||
}
|
||||
|
||||
if (keyUsage[4]) { // KeyUsage.keyAgreement
|
||||
primitives.add(CryptoPrimitive.KEY_AGREEMENT);
|
||||
}
|
||||
|
||||
// KeyUsage.encipherOnly and KeyUsage.decipherOnly are
|
||||
// undefined in the absence of the keyAgreement bit.
|
||||
|
||||
if (primitives.isEmpty()) {
|
||||
throw new CertPathValidatorException(
|
||||
"incorrect KeyUsage extension bits",
|
||||
null, null, -1, PKIXReason.INVALID_KEY_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
ConstraintsParameters cp =
|
||||
new CertPathConstraintsParameters(x509Cert, variant,
|
||||
anchor, date);
|
||||
|
||||
// Check against local constraints if it is DisabledAlgorithmConstraints
|
||||
if (constraints instanceof DisabledAlgorithmConstraints) {
|
||||
((DisabledAlgorithmConstraints)constraints).permits(currSigAlg,
|
||||
currSigAlgParams, cp, true);
|
||||
// DisabledAlgorithmsConstraints does not check primitives, so key
|
||||
// additional key check.
|
||||
|
||||
} else {
|
||||
// Perform the default constraints checking anyway.
|
||||
certPathDefaultConstraints.permits(currSigAlg, currSigAlgParams, cp, true);
|
||||
// Call locally set constraints to check key with primitives.
|
||||
if (!constraints.permits(primitives, currPubKey)) {
|
||||
throw new CertPathValidatorException(
|
||||
"Algorithm constraints check failed on key " +
|
||||
currPubKey.getAlgorithm() + " with size of " +
|
||||
sun.security.util.KeyUtil.getKeySize(currPubKey) +
|
||||
"bits",
|
||||
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no previous key, set one and exit
|
||||
if (prevPubKey == null) {
|
||||
prevPubKey = currPubKey;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check with previous cert for signature algorithm and public key
|
||||
if (!constraints.permits(
|
||||
SIGNATURE_PRIMITIVE_SET,
|
||||
currSigAlg, prevPubKey, currSigAlgParams)) {
|
||||
throw new CertPathValidatorException(
|
||||
"Algorithm constraints check failed on " +
|
||||
"signature algorithm: " + currSigAlg,
|
||||
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
|
||||
}
|
||||
|
||||
// Inherit key parameters from previous key
|
||||
if (PKIX.isDSAPublicKeyWithoutParams(currPubKey)) {
|
||||
// Inherit DSA parameters from previous key
|
||||
if (!(prevPubKey instanceof DSAPublicKey)) {
|
||||
throw new CertPathValidatorException("Input key is not " +
|
||||
"of a appropriate type for inheriting parameters");
|
||||
}
|
||||
|
||||
DSAParams params = ((DSAPublicKey)prevPubKey).getParams();
|
||||
if (params == null) {
|
||||
throw new CertPathValidatorException(
|
||||
"Key parameters missing from public key.");
|
||||
}
|
||||
|
||||
try {
|
||||
BigInteger y = ((DSAPublicKey)currPubKey).getY();
|
||||
KeyFactory kf = KeyFactory.getInstance("DSA");
|
||||
DSAPublicKeySpec ks = new DSAPublicKeySpec(y, params.getP(),
|
||||
params.getQ(), params.getG());
|
||||
currPubKey = kf.generatePublic(ks);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new CertPathValidatorException("Unable to generate " +
|
||||
"key with inherited parameters: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// reset the previous public key
|
||||
prevPubKey = currPubKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to set the trust anchor of the checker.
|
||||
* <p>
|
||||
* If there is no trust anchor specified and the checker has not started,
|
||||
* set the trust anchor.
|
||||
*
|
||||
* @param anchor the trust anchor selected to validate the target
|
||||
* certificate
|
||||
*/
|
||||
void trySetTrustAnchor(TrustAnchor anchor) {
|
||||
// Don't bother if the check has started or trust anchor has already
|
||||
// specified.
|
||||
if (prevPubKey == null) {
|
||||
if (anchor == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"The trust anchor cannot be null");
|
||||
}
|
||||
|
||||
// Don't bother to change the trustedPubKey.
|
||||
if (anchor.getTrustedCert() != null) {
|
||||
prevPubKey = anchor.getTrustedCert().getPublicKey();
|
||||
} else {
|
||||
prevPubKey = anchor.getCAPublicKey();
|
||||
}
|
||||
this.anchor = anchor;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the signature algorithm with the specified public key.
|
||||
*
|
||||
* @param key the public key to verify the CRL signature
|
||||
* @param algorithmId signature algorithm Algorithm ID
|
||||
* @param variant the Validator variant of the operation. A null
|
||||
* value passed will set it to Validator.GENERIC.
|
||||
* @param anchor the trust anchor selected to validate the public key
|
||||
*/
|
||||
static void check(PublicKey key, AlgorithmId algorithmId, String variant,
|
||||
TrustAnchor anchor) throws CertPathValidatorException {
|
||||
|
||||
certPathDefaultConstraints.permits(algorithmId.getName(),
|
||||
algorithmId.getParameters(),
|
||||
new CertPathConstraintsParameters(key, variant, anchor), true);
|
||||
}
|
||||
}
|
||||
|
||||
302
jdkSrc/jdk8/sun/security/provider/certpath/BasicChecker.java
Normal file
302
jdkSrc/jdk8/sun/security/provider/certpath/BasicChecker.java
Normal file
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.PublicKey;
|
||||
import java.security.SignatureException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateExpiredException;
|
||||
import java.security.cert.CertificateNotYetValidException;
|
||||
import java.security.cert.CertPathValidatorException;
|
||||
import java.security.cert.CertPathValidatorException.BasicReason;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.cert.PKIXCertPathChecker;
|
||||
import java.security.cert.PKIXReason;
|
||||
import java.security.cert.TrustAnchor;
|
||||
import java.security.interfaces.DSAParams;
|
||||
import java.security.interfaces.DSAPublicKey;
|
||||
import java.security.spec.DSAPublicKeySpec;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
import sun.security.x509.X500Name;
|
||||
import sun.security.util.Debug;
|
||||
|
||||
/**
|
||||
* BasicChecker is a PKIXCertPathChecker that checks the basic information
|
||||
* on a PKIX certificate, namely the signature, validity, and subject/issuer
|
||||
* name chaining.
|
||||
*
|
||||
* @since 1.4
|
||||
* @author Yassir Elley
|
||||
*/
|
||||
class BasicChecker extends PKIXCertPathChecker {
|
||||
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
private final PublicKey trustedPubKey;
|
||||
private final X500Principal caName;
|
||||
private final Date date;
|
||||
private final String sigProvider;
|
||||
private final boolean sigOnly;
|
||||
private X500Principal prevSubject;
|
||||
private PublicKey prevPubKey;
|
||||
|
||||
/**
|
||||
* Constructor that initializes the input parameters.
|
||||
*
|
||||
* @param anchor the anchor selected to validate the target certificate
|
||||
* @param testDate the time for which the validity of the certificate
|
||||
* should be determined
|
||||
* @param sigProvider the name of the signature provider
|
||||
* @param sigOnly true if only signature checking is to be done;
|
||||
* if false, all checks are done
|
||||
*/
|
||||
BasicChecker(TrustAnchor anchor, Date date, String sigProvider,
|
||||
boolean sigOnly) {
|
||||
if (anchor.getTrustedCert() != null) {
|
||||
this.trustedPubKey = anchor.getTrustedCert().getPublicKey();
|
||||
this.caName = anchor.getTrustedCert().getSubjectX500Principal();
|
||||
} else {
|
||||
this.trustedPubKey = anchor.getCAPublicKey();
|
||||
this.caName = anchor.getCA();
|
||||
}
|
||||
this.date = date;
|
||||
this.sigProvider = sigProvider;
|
||||
this.sigOnly = sigOnly;
|
||||
this.prevPubKey = trustedPubKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the internal state of the checker from parameters
|
||||
* specified in the constructor.
|
||||
*/
|
||||
@Override
|
||||
public void init(boolean forward) throws CertPathValidatorException {
|
||||
if (!forward) {
|
||||
prevPubKey = trustedPubKey;
|
||||
if (PKIX.isDSAPublicKeyWithoutParams(prevPubKey)) {
|
||||
// If TrustAnchor is a DSA public key and it has no params, it
|
||||
// cannot be used to verify the signature of the first cert,
|
||||
// so throw exception
|
||||
throw new CertPathValidatorException("Key parameters missing");
|
||||
}
|
||||
prevSubject = caName;
|
||||
} else {
|
||||
throw new
|
||||
CertPathValidatorException("forward checking not supported");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForwardCheckingSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedExtensions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the signature, validity, and subject/issuer name chaining
|
||||
* checks on the certificate using its internal state. This method does
|
||||
* not remove any critical extensions from the Collection.
|
||||
*
|
||||
* @param cert the Certificate
|
||||
* @param unresolvedCritExts a Collection of the unresolved critical
|
||||
* extensions
|
||||
* @throws CertPathValidatorException if certificate does not verify
|
||||
*/
|
||||
@Override
|
||||
public void check(Certificate cert, Collection<String> unresolvedCritExts)
|
||||
throws CertPathValidatorException
|
||||
{
|
||||
X509Certificate currCert = (X509Certificate)cert;
|
||||
|
||||
if (!sigOnly) {
|
||||
verifyValidity(currCert);
|
||||
verifyNameChaining(currCert);
|
||||
}
|
||||
verifySignature(currCert);
|
||||
|
||||
updateState(currCert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the signature on the certificate using the previous public key.
|
||||
*
|
||||
* @param cert the X509Certificate
|
||||
* @throws CertPathValidatorException if certificate does not verify
|
||||
*/
|
||||
private void verifySignature(X509Certificate cert)
|
||||
throws CertPathValidatorException
|
||||
{
|
||||
String msg = "signature";
|
||||
if (debug != null)
|
||||
debug.println("---checking " + msg + "...");
|
||||
|
||||
try {
|
||||
cert.verify(prevPubKey, sigProvider);
|
||||
} catch (SignatureException e) {
|
||||
throw new CertPathValidatorException
|
||||
(msg + " check failed", e, null, -1,
|
||||
BasicReason.INVALID_SIGNATURE);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new CertPathValidatorException(msg + " check failed", e);
|
||||
}
|
||||
|
||||
if (debug != null)
|
||||
debug.println(msg + " verified.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to verify the validity on a certificate
|
||||
*/
|
||||
private void verifyValidity(X509Certificate cert)
|
||||
throws CertPathValidatorException
|
||||
{
|
||||
String msg = "validity";
|
||||
if (debug != null)
|
||||
debug.println("---checking " + msg + ":" + date.toString() + "...");
|
||||
|
||||
try {
|
||||
cert.checkValidity(date);
|
||||
} catch (CertificateExpiredException e) {
|
||||
throw new CertPathValidatorException
|
||||
(msg + " check failed", e, null, -1, BasicReason.EXPIRED);
|
||||
} catch (CertificateNotYetValidException e) {
|
||||
throw new CertPathValidatorException
|
||||
(msg + " check failed", e, null, -1, BasicReason.NOT_YET_VALID);
|
||||
}
|
||||
|
||||
if (debug != null)
|
||||
debug.println(msg + " verified.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to check that cert has a valid DN to be next in a chain
|
||||
*/
|
||||
private void verifyNameChaining(X509Certificate cert)
|
||||
throws CertPathValidatorException
|
||||
{
|
||||
if (prevSubject != null) {
|
||||
|
||||
String msg = "subject/issuer name chaining";
|
||||
if (debug != null)
|
||||
debug.println("---checking " + msg + "...");
|
||||
|
||||
X500Principal currIssuer = cert.getIssuerX500Principal();
|
||||
|
||||
// reject null or empty issuer DNs
|
||||
if (X500Name.asX500Name(currIssuer).isEmpty()) {
|
||||
throw new CertPathValidatorException
|
||||
(msg + " check failed: " +
|
||||
"empty/null issuer DN in certificate is invalid", null,
|
||||
null, -1, PKIXReason.NAME_CHAINING);
|
||||
}
|
||||
|
||||
if (!(currIssuer.equals(prevSubject))) {
|
||||
throw new CertPathValidatorException
|
||||
(msg + " check failed", null, null, -1,
|
||||
PKIXReason.NAME_CHAINING);
|
||||
}
|
||||
|
||||
if (debug != null)
|
||||
debug.println(msg + " verified.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to manage state information at each iteration
|
||||
*/
|
||||
private void updateState(X509Certificate currCert)
|
||||
throws CertPathValidatorException
|
||||
{
|
||||
PublicKey cKey = currCert.getPublicKey();
|
||||
if (debug != null) {
|
||||
debug.println("BasicChecker.updateState issuer: " +
|
||||
currCert.getIssuerX500Principal().toString() + "; subject: " +
|
||||
currCert.getSubjectX500Principal() + "; serial#: " +
|
||||
currCert.getSerialNumber().toString());
|
||||
}
|
||||
if (PKIX.isDSAPublicKeyWithoutParams(cKey)) {
|
||||
// cKey needs to inherit DSA parameters from prev key
|
||||
cKey = makeInheritedParamsKey(cKey, prevPubKey);
|
||||
if (debug != null) debug.println("BasicChecker.updateState Made " +
|
||||
"key with inherited params");
|
||||
}
|
||||
prevPubKey = cKey;
|
||||
prevSubject = currCert.getSubjectX500Principal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to create a new key with inherited key parameters.
|
||||
*
|
||||
* @param keyValueKey key from which to obtain key value
|
||||
* @param keyParamsKey key from which to obtain key parameters
|
||||
* @return new public key having value and parameters
|
||||
* @throws CertPathValidatorException if keys are not appropriate types
|
||||
* for this operation
|
||||
*/
|
||||
static PublicKey makeInheritedParamsKey(PublicKey keyValueKey,
|
||||
PublicKey keyParamsKey) throws CertPathValidatorException
|
||||
{
|
||||
if (!(keyValueKey instanceof DSAPublicKey) ||
|
||||
!(keyParamsKey instanceof DSAPublicKey))
|
||||
throw new CertPathValidatorException("Input key is not " +
|
||||
"appropriate type for " +
|
||||
"inheriting parameters");
|
||||
DSAParams params = ((DSAPublicKey)keyParamsKey).getParams();
|
||||
if (params == null)
|
||||
throw new CertPathValidatorException("Key parameters missing");
|
||||
try {
|
||||
BigInteger y = ((DSAPublicKey)keyValueKey).getY();
|
||||
KeyFactory kf = KeyFactory.getInstance("DSA");
|
||||
DSAPublicKeySpec ks = new DSAPublicKeySpec(y,
|
||||
params.getP(),
|
||||
params.getQ(),
|
||||
params.getG());
|
||||
return kf.generatePublic(ks);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new CertPathValidatorException("Unable to generate key with" +
|
||||
" inherited parameters: " +
|
||||
e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return the public key associated with the last certificate processed
|
||||
*
|
||||
* @return PublicKey the last public key processed
|
||||
*/
|
||||
PublicKey getPublicKey() {
|
||||
return prevPubKey;
|
||||
}
|
||||
}
|
||||
277
jdkSrc/jdk8/sun/security/provider/certpath/BuildStep.java
Normal file
277
jdkSrc/jdk8/sun/security/provider/certpath/BuildStep.java
Normal file
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
/**
|
||||
* Describes one step of a certification path build, consisting of a
|
||||
* <code>Vertex</code> state description, a certificate, a possible throwable,
|
||||
* and a result code.
|
||||
*
|
||||
* @author Anne Anderson
|
||||
* @since 1.4
|
||||
* @see sun.security.provider.certpath.Vertex
|
||||
*/
|
||||
public class BuildStep {
|
||||
|
||||
private Vertex vertex;
|
||||
private X509Certificate cert;
|
||||
private Throwable throwable;
|
||||
private int result;
|
||||
|
||||
/**
|
||||
* result code associated with a certificate that may continue a path from
|
||||
* the current certificate.
|
||||
*/
|
||||
public static final int POSSIBLE = 1;
|
||||
|
||||
/**
|
||||
* result code associated with a certificate that was tried, but that
|
||||
* represents an unsuccessful path, so the certificate has been backed out
|
||||
* to allow backtracking to the next possible path.
|
||||
*/
|
||||
public static final int BACK = 2;
|
||||
|
||||
/**
|
||||
* result code associated with a certificate that successfully continues the
|
||||
* current path, but does not yet reach the target.
|
||||
*/
|
||||
public static final int FOLLOW = 3;
|
||||
|
||||
/**
|
||||
* result code associated with a certificate that represents the end of the
|
||||
* last possible path, where no path successfully reached the target.
|
||||
*/
|
||||
public static final int FAIL = 4;
|
||||
|
||||
/**
|
||||
* result code associated with a certificate that represents the end of a
|
||||
* path that successfully reaches the target.
|
||||
*/
|
||||
public static final int SUCCEED = 5;
|
||||
|
||||
/**
|
||||
* construct a BuildStep
|
||||
*
|
||||
* @param vtx description of the vertex at this step
|
||||
* @param res result, where result is one of POSSIBLE, BACK,
|
||||
* FOLLOW, FAIL, SUCCEED
|
||||
*/
|
||||
public BuildStep(Vertex vtx, int res) {
|
||||
vertex = vtx;
|
||||
if (vertex != null) {
|
||||
cert = vertex.getCertificate();
|
||||
throwable = vertex.getThrowable();
|
||||
}
|
||||
result = res;
|
||||
}
|
||||
|
||||
/**
|
||||
* return vertex description for this build step
|
||||
*
|
||||
* @returns Vertex
|
||||
*/
|
||||
public Vertex getVertex() {
|
||||
return vertex;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the certificate associated with this build step
|
||||
*
|
||||
* @returns X509Certificate
|
||||
*/
|
||||
public X509Certificate getCertificate() {
|
||||
return cert;
|
||||
}
|
||||
|
||||
/**
|
||||
* return string form of issuer name from certificate associated with this
|
||||
* build step
|
||||
*
|
||||
* @returns String form of issuer name or null, if no certificate.
|
||||
*/
|
||||
public String getIssuerName() {
|
||||
return getIssuerName(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* return string form of issuer name from certificate associated with this
|
||||
* build step, or a default name if no certificate associated with this
|
||||
* build step, or if issuer name could not be obtained from the certificate.
|
||||
*
|
||||
* @param defaultName name to use as default if unable to return an issuer
|
||||
* name from the certificate, or if no certificate.
|
||||
* @returns String form of issuer name or defaultName, if no certificate or
|
||||
* exception received while trying to extract issuer name from certificate.
|
||||
*/
|
||||
public String getIssuerName(String defaultName) {
|
||||
return (cert == null ? defaultName
|
||||
: cert.getIssuerX500Principal().toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* return string form of subject name from certificate associated with this
|
||||
* build step.
|
||||
*
|
||||
* @returns String form of subject name or null, if no certificate.
|
||||
*/
|
||||
public String getSubjectName() {
|
||||
return getSubjectName(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* return string form of subject name from certificate associated with this
|
||||
* build step, or a default name if no certificate associated with this
|
||||
* build step, or if subject name could not be obtained from the
|
||||
* certificate.
|
||||
*
|
||||
* @param defaultName name to use as default if unable to return a subject
|
||||
* name from the certificate, or if no certificate.
|
||||
* @returns String form of subject name or defaultName, if no certificate or
|
||||
* if an exception was received while attempting to extract the subject name
|
||||
* from the certificate.
|
||||
*/
|
||||
public String getSubjectName(String defaultName) {
|
||||
return (cert == null ? defaultName
|
||||
: cert.getSubjectX500Principal().toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* return the exception associated with this build step.
|
||||
*
|
||||
* @returns Throwable
|
||||
*/
|
||||
public Throwable getThrowable() {
|
||||
return throwable;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the result code associated with this build step. The result codes
|
||||
* are POSSIBLE, FOLLOW, BACK, FAIL, SUCCEED.
|
||||
*
|
||||
* @returns int result code
|
||||
*/
|
||||
public int getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* return a string representing the meaning of the result code associated
|
||||
* with this build step.
|
||||
*
|
||||
* @param res result code
|
||||
* @returns String string representing meaning of the result code
|
||||
*/
|
||||
public String resultToString(int res) {
|
||||
String resultString = "";
|
||||
switch (res) {
|
||||
case POSSIBLE:
|
||||
resultString = "Certificate to be tried.\n";
|
||||
break;
|
||||
case BACK:
|
||||
resultString = "Certificate backed out since path does not "
|
||||
+ "satisfy build requirements.\n";
|
||||
break;
|
||||
case FOLLOW:
|
||||
resultString = "Certificate satisfies conditions.\n";
|
||||
break;
|
||||
case FAIL:
|
||||
resultString = "Certificate backed out since path does not "
|
||||
+ "satisfy conditions.\n";
|
||||
break;
|
||||
case SUCCEED:
|
||||
resultString = "Certificate satisfies conditions.\n";
|
||||
break;
|
||||
default:
|
||||
resultString = "Internal error: Invalid step result value.\n";
|
||||
}
|
||||
return resultString;
|
||||
}
|
||||
|
||||
/**
|
||||
* return a string representation of this build step, showing minimal
|
||||
* detail.
|
||||
*
|
||||
* @returns String
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
String out = "Internal Error\n";
|
||||
switch (result) {
|
||||
case BACK:
|
||||
case FAIL:
|
||||
out = resultToString(result);
|
||||
out = out + vertex.throwableToString();
|
||||
break;
|
||||
case FOLLOW:
|
||||
case SUCCEED:
|
||||
case POSSIBLE:
|
||||
out = resultToString(result);
|
||||
break;
|
||||
default:
|
||||
out = "Internal Error: Invalid step result\n";
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* return a string representation of this build step, showing all detail of
|
||||
* the vertex state appropriate to the result of this build step, and the
|
||||
* certificate contents.
|
||||
*
|
||||
* @returns String
|
||||
*/
|
||||
public String verboseToString() {
|
||||
String out = resultToString(getResult());
|
||||
switch (result) {
|
||||
case BACK:
|
||||
case FAIL:
|
||||
out = out + vertex.throwableToString();
|
||||
break;
|
||||
case FOLLOW:
|
||||
case SUCCEED:
|
||||
out = out + vertex.moreToString();
|
||||
break;
|
||||
case POSSIBLE:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
out = out + "Certificate contains:\n" + vertex.certToString();
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* return a string representation of this build step, including all possible
|
||||
* detail of the vertex state, but not including the certificate contents.
|
||||
*
|
||||
* @returns String
|
||||
*/
|
||||
public String fullToString() {
|
||||
return resultToString(getResult()) + vertex.toString();
|
||||
}
|
||||
}
|
||||
472
jdkSrc/jdk8/sun/security/provider/certpath/Builder.java
Normal file
472
jdkSrc/jdk8/sun/security/provider/certpath/Builder.java
Normal file
@@ -0,0 +1,472 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.AccessController;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.cert.*;
|
||||
import java.util.*;
|
||||
|
||||
import sun.security.action.GetBooleanAction;
|
||||
import sun.security.provider.certpath.PKIX.BuilderParams;
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.x509.GeneralNames;
|
||||
import sun.security.x509.GeneralNameInterface;
|
||||
import sun.security.x509.GeneralSubtrees;
|
||||
import sun.security.x509.NameConstraintsExtension;
|
||||
import sun.security.x509.SubjectAlternativeNameExtension;
|
||||
import sun.security.x509.X500Name;
|
||||
import sun.security.x509.X509CertImpl;
|
||||
|
||||
/**
|
||||
* Abstract class representing a builder, which is able to retrieve
|
||||
* matching certificates and is able to verify a particular certificate.
|
||||
*
|
||||
* @since 1.4
|
||||
* @author Sean Mullan
|
||||
* @author Yassir Elley
|
||||
*/
|
||||
|
||||
public abstract class Builder {
|
||||
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
private Set<String> matchingPolicies;
|
||||
final BuilderParams buildParams;
|
||||
final X509CertSelector targetCertConstraints;
|
||||
|
||||
/**
|
||||
* Flag indicating whether support for the caIssuers field of the
|
||||
* Authority Information Access extension shall be enabled. Currently
|
||||
* disabled by default for compatibility reasons.
|
||||
*/
|
||||
final static boolean USE_AIA = AccessController.doPrivileged
|
||||
(new GetBooleanAction("com.sun.security.enableAIAcaIssuers"));
|
||||
|
||||
/**
|
||||
* Initialize the builder with the input parameters.
|
||||
*
|
||||
* @param params the parameter set used to build a certification path
|
||||
*/
|
||||
Builder(BuilderParams buildParams) {
|
||||
this.buildParams = buildParams;
|
||||
this.targetCertConstraints =
|
||||
(X509CertSelector)buildParams.targetCertConstraints();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves certificates from the list of certStores using the buildParams
|
||||
* and the currentState as a filter
|
||||
*
|
||||
* @param currentState the current State
|
||||
* @param certStores list of CertStores
|
||||
*/
|
||||
abstract Collection<X509Certificate> getMatchingCerts
|
||||
(State currentState, List<CertStore> certStores)
|
||||
throws CertStoreException, CertificateException, IOException;
|
||||
|
||||
/**
|
||||
* Verifies the cert against the currentState, using the certPathList
|
||||
* generated thus far to help with loop detection
|
||||
*
|
||||
* @param cert the certificate to be verified
|
||||
* @param currentState the current state against which the cert is verified
|
||||
* @param certPathList the certPathList generated thus far
|
||||
*/
|
||||
abstract void verifyCert(X509Certificate cert, State currentState,
|
||||
List<X509Certificate> certPathList)
|
||||
throws GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* Verifies whether the input certificate completes the path.
|
||||
* When building in the forward direction, a trust anchor will
|
||||
* complete the path.
|
||||
*
|
||||
* @param cert the certificate to test
|
||||
* @return a boolean value indicating whether the cert completes the path.
|
||||
*/
|
||||
abstract boolean isPathCompleted(X509Certificate cert);
|
||||
|
||||
/**
|
||||
* Adds the certificate to the certPathList
|
||||
*
|
||||
* @param cert the certificate to be added
|
||||
* @param certPathList the certification path list
|
||||
*/
|
||||
abstract void addCertToPath(X509Certificate cert,
|
||||
LinkedList<X509Certificate> certPathList);
|
||||
|
||||
/**
|
||||
* Removes final certificate from the certPathList
|
||||
*
|
||||
* @param certPathList the certification path list
|
||||
*/
|
||||
abstract void removeFinalCertFromPath
|
||||
(LinkedList<X509Certificate> certPathList);
|
||||
|
||||
/**
|
||||
* get distance of one GeneralName from another
|
||||
*
|
||||
* @param base GeneralName at base of subtree
|
||||
* @param test GeneralName to be tested against base
|
||||
* @param incomparable the value to return if the names are
|
||||
* incomparable
|
||||
* @return distance of test name from base, where 0
|
||||
* means exact match, 1 means test is an immediate
|
||||
* child of base, 2 means test is a grandchild, etc.
|
||||
* -1 means test is a parent of base, -2 means test
|
||||
* is a grandparent, etc.
|
||||
*/
|
||||
static int distance(GeneralNameInterface base,
|
||||
GeneralNameInterface test, int incomparable)
|
||||
{
|
||||
switch (base.constrains(test)) {
|
||||
case GeneralNameInterface.NAME_DIFF_TYPE:
|
||||
if (debug != null) {
|
||||
debug.println("Builder.distance(): Names are different types");
|
||||
}
|
||||
return incomparable;
|
||||
case GeneralNameInterface.NAME_SAME_TYPE:
|
||||
if (debug != null) {
|
||||
debug.println("Builder.distance(): Names are same type but " +
|
||||
"in different subtrees");
|
||||
}
|
||||
return incomparable;
|
||||
case GeneralNameInterface.NAME_MATCH:
|
||||
return 0;
|
||||
case GeneralNameInterface.NAME_WIDENS:
|
||||
break;
|
||||
case GeneralNameInterface.NAME_NARROWS:
|
||||
break;
|
||||
default: // should never occur
|
||||
return incomparable;
|
||||
}
|
||||
|
||||
/* names are in same subtree */
|
||||
return test.subtreeDepth() - base.subtreeDepth();
|
||||
}
|
||||
|
||||
/**
|
||||
* get hop distance of one GeneralName from another in links where
|
||||
* the names need not have an ancestor/descendant relationship.
|
||||
* For example, the hop distance from ou=D,ou=C,o=B,c=US to
|
||||
* ou=F,ou=E,ou=C,o=B,c=US is 3: D->C, C->E, E->F. The hop distance
|
||||
* from ou=C,o=B,c=US to ou=D,ou=C,o=B,c=US is -1: C->D
|
||||
*
|
||||
* @param base GeneralName
|
||||
* @param test GeneralName to be tested against base
|
||||
* @param incomparable the value to return if the names are
|
||||
* incomparable
|
||||
* @return distance of test name from base measured in hops in the
|
||||
* namespace hierarchy, where 0 means exact match. Result
|
||||
* is positive if path is some number of up hops followed by
|
||||
* some number of down hops; result is negative if path is
|
||||
* some number of down hops.
|
||||
*/
|
||||
static int hops(GeneralNameInterface base, GeneralNameInterface test,
|
||||
int incomparable)
|
||||
{
|
||||
int baseRtest = base.constrains(test);
|
||||
switch (baseRtest) {
|
||||
case GeneralNameInterface.NAME_DIFF_TYPE:
|
||||
if (debug != null) {
|
||||
debug.println("Builder.hops(): Names are different types");
|
||||
}
|
||||
return incomparable;
|
||||
case GeneralNameInterface.NAME_SAME_TYPE:
|
||||
/* base and test are in different subtrees */
|
||||
break;
|
||||
case GeneralNameInterface.NAME_MATCH:
|
||||
/* base matches test */
|
||||
return 0;
|
||||
case GeneralNameInterface.NAME_WIDENS:
|
||||
/* base is ancestor of test */
|
||||
return (test.subtreeDepth()-base.subtreeDepth());
|
||||
case GeneralNameInterface.NAME_NARROWS:
|
||||
/* base is descendant of test */
|
||||
return (test.subtreeDepth()-base.subtreeDepth());
|
||||
default: // should never occur
|
||||
return incomparable;
|
||||
}
|
||||
|
||||
/* names are in different subtrees */
|
||||
if (base.getType() != GeneralNameInterface.NAME_DIRECTORY) {
|
||||
if (debug != null) {
|
||||
debug.println("Builder.hops(): hopDistance not implemented " +
|
||||
"for this name type");
|
||||
}
|
||||
return incomparable;
|
||||
}
|
||||
X500Name baseName = (X500Name)base;
|
||||
X500Name testName = (X500Name)test;
|
||||
X500Name commonName = baseName.commonAncestor(testName);
|
||||
if (commonName == null) {
|
||||
if (debug != null) {
|
||||
debug.println("Builder.hops(): Names are in different " +
|
||||
"namespaces");
|
||||
}
|
||||
return incomparable;
|
||||
} else {
|
||||
int commonDistance = commonName.subtreeDepth();
|
||||
int baseDistance = baseName.subtreeDepth();
|
||||
int testDistance = testName.subtreeDepth();
|
||||
return (baseDistance + testDistance - (2 * commonDistance));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine how close a given certificate gets you toward
|
||||
* a given target.
|
||||
*
|
||||
* @param constraints Current NameConstraints; if null,
|
||||
* then caller must verify NameConstraints
|
||||
* independently, realizing that this certificate
|
||||
* may not actually lead to the target at all.
|
||||
* @param cert Candidate certificate for chain
|
||||
* @param target GeneralNameInterface name of target
|
||||
* @return distance from this certificate to target:
|
||||
* <ul>
|
||||
* <li>-1 means certificate could be CA for target, but
|
||||
* there are no NameConstraints limiting how close
|
||||
* <li> 0 means certificate subject or subjectAltName
|
||||
* matches target
|
||||
* <li> 1 means certificate is permitted to be CA for
|
||||
* target.
|
||||
* <li> 2 means certificate is permitted to be CA for
|
||||
* parent of target.
|
||||
* <li>>0 in general, means certificate is permitted
|
||||
* to be a CA for this distance higher in the naming
|
||||
* hierarchy than the target, plus 1.
|
||||
* </ul>
|
||||
* <p>Note that the subject and/or subjectAltName of the
|
||||
* candidate cert does not have to be an ancestor of the
|
||||
* target in order to be a CA that can issue a certificate to
|
||||
* the target. In these cases, the target distance is calculated
|
||||
* by inspecting the NameConstraints extension in the candidate
|
||||
* certificate. For example, suppose the target is an X.500 DN with
|
||||
* a value of "CN=mullan,OU=ireland,O=sun,C=us" and the
|
||||
* NameConstraints extension in the candidate certificate
|
||||
* includes a permitted component of "O=sun,C=us", which implies
|
||||
* that the candidate certificate is allowed to issue certs in
|
||||
* the "O=sun,C=us" namespace. The target distance is 3
|
||||
* ((distance of permitted NC from target) + 1).
|
||||
* The (+1) is added to distinguish the result from the case
|
||||
* which returns (0).
|
||||
* @throws IOException if certificate does not get closer
|
||||
*/
|
||||
static int targetDistance(NameConstraintsExtension constraints,
|
||||
X509Certificate cert, GeneralNameInterface target)
|
||||
throws IOException
|
||||
{
|
||||
/* ensure that certificate satisfies existing name constraints */
|
||||
if (constraints != null && !constraints.verify(cert)) {
|
||||
throw new IOException("certificate does not satisfy existing name "
|
||||
+ "constraints");
|
||||
}
|
||||
|
||||
X509CertImpl certImpl;
|
||||
try {
|
||||
certImpl = X509CertImpl.toImpl(cert);
|
||||
} catch (CertificateException e) {
|
||||
throw new IOException("Invalid certificate", e);
|
||||
}
|
||||
/* see if certificate subject matches target */
|
||||
X500Name subject = X500Name.asX500Name(certImpl.getSubjectX500Principal());
|
||||
if (subject.equals(target)) {
|
||||
/* match! */
|
||||
return 0;
|
||||
}
|
||||
|
||||
SubjectAlternativeNameExtension altNameExt =
|
||||
certImpl.getSubjectAlternativeNameExtension();
|
||||
if (altNameExt != null) {
|
||||
GeneralNames altNames = altNameExt.get(
|
||||
SubjectAlternativeNameExtension.SUBJECT_NAME);
|
||||
/* see if any alternative name matches target */
|
||||
if (altNames != null) {
|
||||
for (int j = 0, n = altNames.size(); j < n; j++) {
|
||||
GeneralNameInterface altName = altNames.get(j).getName();
|
||||
if (altName.equals(target)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* no exact match; see if certificate can get us to target */
|
||||
|
||||
/* first, get NameConstraints out of certificate */
|
||||
NameConstraintsExtension ncExt = certImpl.getNameConstraintsExtension();
|
||||
if (ncExt == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* merge certificate's NameConstraints with current NameConstraints */
|
||||
if (constraints != null) {
|
||||
constraints.merge(ncExt);
|
||||
} else {
|
||||
// Make sure we do a clone here, because we're probably
|
||||
// going to modify this object later and we don't want to
|
||||
// be sharing it with a Certificate object!
|
||||
constraints = (NameConstraintsExtension) ncExt.clone();
|
||||
}
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("Builder.targetDistance() merged constraints: "
|
||||
+ String.valueOf(constraints));
|
||||
}
|
||||
/* reduce permitted by excluded */
|
||||
GeneralSubtrees permitted =
|
||||
constraints.get(NameConstraintsExtension.PERMITTED_SUBTREES);
|
||||
GeneralSubtrees excluded =
|
||||
constraints.get(NameConstraintsExtension.EXCLUDED_SUBTREES);
|
||||
if (permitted != null) {
|
||||
permitted.reduce(excluded);
|
||||
}
|
||||
if (debug != null) {
|
||||
debug.println("Builder.targetDistance() reduced constraints: "
|
||||
+ permitted);
|
||||
}
|
||||
/* see if new merged constraints allow target */
|
||||
if (!constraints.verify(target)) {
|
||||
throw new IOException("New certificate not allowed to sign "
|
||||
+ "certificate for target");
|
||||
}
|
||||
/* find distance to target, if any, in permitted */
|
||||
if (permitted == null) {
|
||||
/* certificate is unconstrained; could sign for anything */
|
||||
return -1;
|
||||
}
|
||||
for (int i = 0, n = permitted.size(); i < n; i++) {
|
||||
GeneralNameInterface perName = permitted.get(i).getName().getName();
|
||||
int distance = distance(perName, target, -1);
|
||||
if (distance >= 0) {
|
||||
return (distance + 1);
|
||||
}
|
||||
}
|
||||
/* no matching type in permitted; cert holder could certify target */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method can be used as an optimization to filter out
|
||||
* certificates that do not have policies which are valid.
|
||||
* It returns the set of policies (String OIDs) that should exist in
|
||||
* the certificate policies extension of the certificate that is
|
||||
* needed by the builder. The logic applied is as follows:
|
||||
* <p>
|
||||
* 1) If some initial policies have been set *and* policy mappings are
|
||||
* inhibited, then acceptable certificates are those that include
|
||||
* the ANY_POLICY OID or with policies that intersect with the
|
||||
* initial policies.
|
||||
* 2) If no initial policies have been set *or* policy mappings are
|
||||
* not inhibited then we don't have much to work with. All we know is
|
||||
* that a certificate must have *some* policy because if it didn't
|
||||
* have any policy then the policy tree would become null (and validation
|
||||
* would fail).
|
||||
*
|
||||
* @return the Set of policies any of which must exist in a
|
||||
* cert's certificate policies extension in order for a cert to be selected.
|
||||
*/
|
||||
Set<String> getMatchingPolicies() {
|
||||
if (matchingPolicies != null) {
|
||||
Set<String> initialPolicies = buildParams.initialPolicies();
|
||||
if ((!initialPolicies.isEmpty()) &&
|
||||
(!initialPolicies.contains(PolicyChecker.ANY_POLICY)) &&
|
||||
(buildParams.policyMappingInhibited()))
|
||||
{
|
||||
matchingPolicies = new HashSet<>(initialPolicies);
|
||||
matchingPolicies.add(PolicyChecker.ANY_POLICY);
|
||||
} else {
|
||||
// we just return an empty set to make sure that there is
|
||||
// at least a certificate policies extension in the cert
|
||||
matchingPolicies = Collections.<String>emptySet();
|
||||
}
|
||||
}
|
||||
return matchingPolicies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the specified CertStores and add all certificates matching
|
||||
* selector to resultCerts.
|
||||
*
|
||||
* If the targetCert criterion of the selector is set, only that cert
|
||||
* is examined and the CertStores are not searched.
|
||||
*
|
||||
* If checkAll is true, all CertStores are searched for matching certs.
|
||||
* If false, the method returns as soon as the first CertStore returns
|
||||
* a matching cert(s).
|
||||
*
|
||||
* Returns true iff resultCerts changed (a cert was added to the collection)
|
||||
*/
|
||||
boolean addMatchingCerts(X509CertSelector selector,
|
||||
Collection<CertStore> certStores,
|
||||
Collection<X509Certificate> resultCerts,
|
||||
boolean checkAll)
|
||||
{
|
||||
X509Certificate targetCert = selector.getCertificate();
|
||||
if (targetCert != null) {
|
||||
// no need to search CertStores
|
||||
if (selector.match(targetCert)) {
|
||||
if (debug != null) {
|
||||
debug.println("Builder.addMatchingCerts: " +
|
||||
"adding target cert" +
|
||||
"\n SN: " + Debug.toHexString(
|
||||
targetCert.getSerialNumber()) +
|
||||
"\n Subject: " + targetCert.getSubjectX500Principal() +
|
||||
"\n Issuer: " + targetCert.getIssuerX500Principal());
|
||||
}
|
||||
return resultCerts.add(targetCert);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
boolean add = false;
|
||||
for (CertStore store : certStores) {
|
||||
try {
|
||||
Collection<? extends Certificate> certs =
|
||||
store.getCertificates(selector);
|
||||
for (Certificate cert : certs) {
|
||||
if (resultCerts.add((X509Certificate)cert)) {
|
||||
add = true;
|
||||
}
|
||||
}
|
||||
if (!checkAll && add) {
|
||||
return true;
|
||||
}
|
||||
} catch (CertStoreException cse) {
|
||||
// if getCertificates throws a CertStoreException, we ignore
|
||||
// it and move on to the next CertStore
|
||||
if (debug != null) {
|
||||
debug.println("Builder.addMatchingCerts, non-fatal " +
|
||||
"exception retrieving certs: " + cse);
|
||||
cse.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return add;
|
||||
}
|
||||
}
|
||||
235
jdkSrc/jdk8/sun/security/provider/certpath/CertId.java
Normal file
235
jdkSrc/jdk8/sun/security/provider/certpath/CertId.java
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
import sun.misc.HexDumpEncoder;
|
||||
import sun.security.x509.*;
|
||||
import sun.security.util.*;
|
||||
|
||||
/**
|
||||
* This class corresponds to the CertId field in OCSP Request
|
||||
* and the OCSP Response. The ASN.1 definition for CertID is defined
|
||||
* in RFC 2560 as:
|
||||
* <pre>
|
||||
*
|
||||
* CertID ::= SEQUENCE {
|
||||
* hashAlgorithm AlgorithmIdentifier,
|
||||
* issuerNameHash OCTET STRING, -- Hash of Issuer's DN
|
||||
* issuerKeyHash OCTET STRING, -- Hash of Issuers public key
|
||||
* serialNumber CertificateSerialNumber
|
||||
* }
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author Ram Marti
|
||||
*/
|
||||
|
||||
public class CertId {
|
||||
|
||||
private static final boolean debug = false;
|
||||
private static final AlgorithmId SHA1_ALGID
|
||||
= new AlgorithmId(AlgorithmId.SHA_oid);
|
||||
private final AlgorithmId hashAlgId;
|
||||
private final byte[] issuerNameHash;
|
||||
private final byte[] issuerKeyHash;
|
||||
private final SerialNumber certSerialNumber;
|
||||
private int myhash = -1; // hashcode for this CertId
|
||||
|
||||
/**
|
||||
* Creates a CertId. The hash algorithm used is SHA-1.
|
||||
*/
|
||||
public CertId(X509Certificate issuerCert, SerialNumber serialNumber)
|
||||
throws IOException {
|
||||
|
||||
this(issuerCert.getSubjectX500Principal(),
|
||||
issuerCert.getPublicKey(), serialNumber);
|
||||
}
|
||||
|
||||
public CertId(X500Principal issuerName, PublicKey issuerKey,
|
||||
SerialNumber serialNumber) throws IOException {
|
||||
|
||||
// compute issuerNameHash
|
||||
MessageDigest md = null;
|
||||
try {
|
||||
md = MessageDigest.getInstance("SHA1");
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
throw new IOException("Unable to create CertId", nsae);
|
||||
}
|
||||
hashAlgId = SHA1_ALGID;
|
||||
md.update(issuerName.getEncoded());
|
||||
issuerNameHash = md.digest();
|
||||
|
||||
// compute issuerKeyHash (remove the tag and length)
|
||||
byte[] pubKey = issuerKey.getEncoded();
|
||||
DerValue val = new DerValue(pubKey);
|
||||
DerValue[] seq = new DerValue[2];
|
||||
seq[0] = val.data.getDerValue(); // AlgorithmID
|
||||
seq[1] = val.data.getDerValue(); // Key
|
||||
byte[] keyBytes = seq[1].getBitString();
|
||||
md.update(keyBytes);
|
||||
issuerKeyHash = md.digest();
|
||||
certSerialNumber = serialNumber;
|
||||
|
||||
if (debug) {
|
||||
HexDumpEncoder encoder = new HexDumpEncoder();
|
||||
System.out.println("Issuer Name is " + issuerName);
|
||||
System.out.println("issuerNameHash is " +
|
||||
encoder.encodeBuffer(issuerNameHash));
|
||||
System.out.println("issuerKeyHash is " +
|
||||
encoder.encodeBuffer(issuerKeyHash));
|
||||
System.out.println("SerialNumber is " + serialNumber.getNumber());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a CertId from its ASN.1 DER encoding.
|
||||
*/
|
||||
public CertId(DerInputStream derIn) throws IOException {
|
||||
hashAlgId = AlgorithmId.parse(derIn.getDerValue());
|
||||
issuerNameHash = derIn.getOctetString();
|
||||
issuerKeyHash = derIn.getOctetString();
|
||||
certSerialNumber = new SerialNumber(derIn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash algorithm identifier.
|
||||
*/
|
||||
public AlgorithmId getHashAlgorithm() {
|
||||
return hashAlgId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash value for the issuer name.
|
||||
*/
|
||||
public byte[] getIssuerNameHash() {
|
||||
return issuerNameHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash value for the issuer key.
|
||||
*/
|
||||
public byte[] getIssuerKeyHash() {
|
||||
return issuerKeyHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the serial number.
|
||||
*/
|
||||
public BigInteger getSerialNumber() {
|
||||
return certSerialNumber.getNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the CertId using ASN.1 DER.
|
||||
* The hash algorithm used is SHA-1.
|
||||
*/
|
||||
public void encode(DerOutputStream out) throws IOException {
|
||||
|
||||
DerOutputStream tmp = new DerOutputStream();
|
||||
hashAlgId.encode(tmp);
|
||||
tmp.putOctetString(issuerNameHash);
|
||||
tmp.putOctetString(issuerKeyHash);
|
||||
certSerialNumber.encode(tmp);
|
||||
out.write(DerValue.tag_Sequence, tmp);
|
||||
|
||||
if (debug) {
|
||||
HexDumpEncoder encoder = new HexDumpEncoder();
|
||||
System.out.println("Encoded certId is " +
|
||||
encoder.encode(out.toByteArray()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hashcode value for this CertId.
|
||||
*
|
||||
* @return the hashcode value.
|
||||
*/
|
||||
@Override public int hashCode() {
|
||||
if (myhash == -1) {
|
||||
myhash = hashAlgId.hashCode();
|
||||
for (int i = 0; i < issuerNameHash.length; i++) {
|
||||
myhash += issuerNameHash[i] * i;
|
||||
}
|
||||
for (int i = 0; i < issuerKeyHash.length; i++) {
|
||||
myhash += issuerKeyHash[i] * i;
|
||||
}
|
||||
myhash += certSerialNumber.getNumber().hashCode();
|
||||
}
|
||||
return myhash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this CertId for equality with the specified
|
||||
* object. Two CertId objects are considered equal if their hash algorithms,
|
||||
* their issuer name and issuer key hash values and their serial numbers
|
||||
* are equal.
|
||||
*
|
||||
* @param other the object to test for equality with this object.
|
||||
* @return true if the objects are considered equal, false otherwise.
|
||||
*/
|
||||
@Override public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (other == null || (!(other instanceof CertId))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CertId that = (CertId) other;
|
||||
if (hashAlgId.equals(that.getHashAlgorithm()) &&
|
||||
Arrays.equals(issuerNameHash, that.getIssuerNameHash()) &&
|
||||
Arrays.equals(issuerKeyHash, that.getIssuerKeyHash()) &&
|
||||
certSerialNumber.getNumber().equals(that.getSerialNumber())) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a string representation of the CertId.
|
||||
*/
|
||||
@Override public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("CertId \n");
|
||||
sb.append("Algorithm: " + hashAlgId.toString() +"\n");
|
||||
sb.append("issuerNameHash \n");
|
||||
HexDumpEncoder encoder = new HexDumpEncoder();
|
||||
sb.append(encoder.encode(issuerNameHash));
|
||||
sb.append("\nissuerKeyHash: \n");
|
||||
sb.append(encoder.encode(issuerKeyHash));
|
||||
sb.append("\n" + certSerialNumber.toString());
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.security.Key;
|
||||
import java.security.cert.TrustAnchor;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
import java.util.Collections;
|
||||
|
||||
import sun.security.util.ConstraintsParameters;
|
||||
import sun.security.validator.Validator;
|
||||
|
||||
/**
|
||||
* This class contains parameters for checking certificates against
|
||||
* constraints specified in the jdk.certpath.disabledAlgorithms security
|
||||
* property.
|
||||
*/
|
||||
public class CertPathConstraintsParameters implements ConstraintsParameters {
|
||||
// The public key of the certificate
|
||||
private final Key key;
|
||||
// The certificate's trust anchor which will be checked against the
|
||||
// jdkCA constraint, if specified.
|
||||
private final TrustAnchor anchor;
|
||||
// The PKIXParameter validity date or the timestamp of the signed JAR
|
||||
// file, if this chain is associated with a timestamped signed JAR.
|
||||
private final Date date;
|
||||
// The variant or usage of this certificate
|
||||
private final String variant;
|
||||
// The certificate being checked (may be null if a CRL or OCSPResponse is
|
||||
// being checked)
|
||||
private final X509Certificate cert;
|
||||
|
||||
public CertPathConstraintsParameters(X509Certificate cert,
|
||||
String variant, TrustAnchor anchor, Date date) {
|
||||
this(cert.getPublicKey(), variant, anchor, date, cert);
|
||||
}
|
||||
|
||||
public CertPathConstraintsParameters(Key key, String variant,
|
||||
TrustAnchor anchor) {
|
||||
this(key, variant, anchor, null, null);
|
||||
}
|
||||
|
||||
private CertPathConstraintsParameters(Key key, String variant,
|
||||
TrustAnchor anchor, Date date, X509Certificate cert) {
|
||||
this.key = key;
|
||||
this.variant = (variant == null ? Validator.VAR_GENERIC : variant);
|
||||
this.anchor = anchor;
|
||||
this.date = date;
|
||||
this.cert = cert;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean anchorIsJdkCA() {
|
||||
return CertPathHelper.isJdkCA(anchor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Key> getKeys() {
|
||||
return (key == null) ? Collections.emptySet()
|
||||
: Collections.singleton(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVariant() {
|
||||
return variant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String extendedExceptionMsg() {
|
||||
return (cert == null ? "."
|
||||
: " used with certificate: " +
|
||||
cert.getSubjectX500Principal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("[\n");
|
||||
sb.append(" Variant: ").append(variant);
|
||||
if (anchor != null) {
|
||||
sb.append("\n Anchor: ").append(anchor);
|
||||
}
|
||||
if (cert != null) {
|
||||
sb.append("\n Cert Issuer: ")
|
||||
.append(cert.getIssuerX500Principal());
|
||||
sb.append("\n Cert Subject: ")
|
||||
.append(cert.getSubjectX500Principal());
|
||||
}
|
||||
if (key != null) {
|
||||
sb.append("\n Key: ").append(key.getAlgorithm());
|
||||
}
|
||||
if (date != null) {
|
||||
sb.append("\n Date: ").append(date);
|
||||
}
|
||||
sb.append("\n]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import java.security.cert.TrustAnchor;
|
||||
import java.security.cert.X509CRLSelector;
|
||||
|
||||
/**
|
||||
* Helper class that allows access to JDK specific known-public methods in the
|
||||
* java.security.cert package. It relies on a subclass in the
|
||||
* java.security.cert packages that is initialized before any of these methods
|
||||
* are called (achieved via static initializers).
|
||||
*
|
||||
* The methods are made available in this fashion for performance reasons.
|
||||
*
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public abstract class CertPathHelper {
|
||||
|
||||
/**
|
||||
* Object used to tunnel the calls. Initialized by CertPathHelperImpl.
|
||||
*/
|
||||
protected static CertPathHelper instance;
|
||||
|
||||
protected CertPathHelper() {
|
||||
// empty
|
||||
}
|
||||
|
||||
protected abstract void implSetDateAndTime(X509CRLSelector sel, Date date, long skew);
|
||||
|
||||
protected abstract boolean implIsJdkCA(TrustAnchor anchor);
|
||||
|
||||
public static void setDateAndTime(X509CRLSelector sel, Date date, long skew) {
|
||||
instance.implSetDateAndTime(sel, date, skew);
|
||||
}
|
||||
|
||||
public static boolean isJdkCA(TrustAnchor anchor) {
|
||||
return (anchor == null) ? false : instance.implIsJdkCA(anchor);
|
||||
}
|
||||
}
|
||||
148
jdkSrc/jdk8/sun/security/provider/certpath/CertStoreHelper.java
Normal file
148
jdkSrc/jdk8/sun/security/provider/certpath/CertStoreHelper.java
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.security.AccessController;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.security.cert.CertStore;
|
||||
import java.security.cert.CertStoreException;
|
||||
import java.security.cert.X509CertSelector;
|
||||
import java.security.cert.X509CRLSelector;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
import java.io.IOException;
|
||||
|
||||
import sun.security.util.Cache;
|
||||
|
||||
/**
|
||||
* Helper used by URICertStore and others when delegating to another CertStore
|
||||
* to fetch certs and CRLs.
|
||||
*/
|
||||
|
||||
public abstract class CertStoreHelper {
|
||||
|
||||
private static final int NUM_TYPES = 2;
|
||||
private final static Map<String,String> classMap = new HashMap<>(NUM_TYPES);
|
||||
static {
|
||||
classMap.put(
|
||||
"LDAP",
|
||||
"sun.security.provider.certpath.ldap.LDAPCertStoreHelper");
|
||||
classMap.put(
|
||||
"SSLServer",
|
||||
"sun.security.provider.certpath.ssl.SSLServerCertStoreHelper");
|
||||
};
|
||||
private static Cache<String, CertStoreHelper> cache
|
||||
= Cache.newSoftMemoryCache(NUM_TYPES);
|
||||
|
||||
public static CertStoreHelper getInstance(final String type)
|
||||
throws NoSuchAlgorithmException
|
||||
{
|
||||
CertStoreHelper helper = cache.get(type);
|
||||
if (helper != null) {
|
||||
return helper;
|
||||
}
|
||||
final String cl = classMap.get(type);
|
||||
if (cl == null) {
|
||||
throw new NoSuchAlgorithmException(type + " not available");
|
||||
}
|
||||
try {
|
||||
helper = AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<CertStoreHelper>() {
|
||||
public CertStoreHelper run() throws ClassNotFoundException {
|
||||
try {
|
||||
Class<?> c = Class.forName(cl, true, null);
|
||||
CertStoreHelper csh
|
||||
= (CertStoreHelper)c.newInstance();
|
||||
cache.put(type, csh);
|
||||
return csh;
|
||||
} catch (InstantiationException |
|
||||
IllegalAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
return helper;
|
||||
} catch (PrivilegedActionException e) {
|
||||
throw new NoSuchAlgorithmException(type + " not available",
|
||||
e.getException());
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isCausedByNetworkIssue(String type, CertStoreException cse) {
|
||||
switch (type) {
|
||||
case "LDAP":
|
||||
case "SSLServer":
|
||||
try {
|
||||
CertStoreHelper csh = CertStoreHelper.getInstance(type);
|
||||
return csh.isCausedByNetworkIssue(cse);
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
return false;
|
||||
}
|
||||
case "URI":
|
||||
Throwable t = cse.getCause();
|
||||
return (t != null && t instanceof IOException);
|
||||
default:
|
||||
// we don't know about any other remote CertStore types
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a CertStore using the given URI as parameters.
|
||||
*/
|
||||
public abstract CertStore getCertStore(URI uri)
|
||||
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException;
|
||||
|
||||
/**
|
||||
* Wraps an existing X509CertSelector when needing to avoid DN matching
|
||||
* issues.
|
||||
*/
|
||||
public abstract X509CertSelector wrap(X509CertSelector selector,
|
||||
X500Principal certSubject,
|
||||
String dn)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Wraps an existing X509CRLSelector when needing to avoid DN matching
|
||||
* issues.
|
||||
*/
|
||||
public abstract X509CRLSelector wrap(X509CRLSelector selector,
|
||||
Collection<X500Principal> certIssuers,
|
||||
String dn)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Returns true if the cause of the CertStoreException is a network
|
||||
* related issue.
|
||||
*/
|
||||
public abstract boolean isCausedByNetworkIssue(CertStoreException e);
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CRL;
|
||||
import java.util.Collection;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.HashSet;
|
||||
import java.security.cert.CertSelector;
|
||||
import java.security.cert.CertStore;
|
||||
import java.security.cert.CertStoreException;
|
||||
import java.security.cert.CertStoreParameters;
|
||||
import java.security.cert.CollectionCertStoreParameters;
|
||||
import java.security.cert.CRLSelector;
|
||||
import java.security.cert.CertStoreSpi;
|
||||
|
||||
/**
|
||||
* A <code>CertStore</code> that retrieves <code>Certificates</code> and
|
||||
* <code>CRL</code>s from a <code>Collection</code>.
|
||||
* <p>
|
||||
* Before calling the {@link #engineGetCertificates engineGetCertificates} or
|
||||
* {@link #engineGetCRLs engineGetCRLs} methods, the
|
||||
* {@link #CollectionCertStore(CertStoreParameters)
|
||||
* CollectionCertStore(CertStoreParameters)} constructor is called to
|
||||
* create the <code>CertStore</code> and establish the
|
||||
* <code>Collection</code> from which <code>Certificate</code>s and
|
||||
* <code>CRL</code>s will be retrieved. If the specified
|
||||
* <code>Collection</code> contains an object that is not a
|
||||
* <code>Certificate</code> or <code>CRL</code>, that object will be
|
||||
* ignored.
|
||||
* <p>
|
||||
* <b>Concurrent Access</b>
|
||||
* <p>
|
||||
* As described in the javadoc for <code>CertStoreSpi</code>, the
|
||||
* <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods
|
||||
* must be thread-safe. That is, multiple threads may concurrently
|
||||
* invoke these methods on a single <code>CollectionCertStore</code>
|
||||
* object (or more than one) with no ill effects.
|
||||
* <p>
|
||||
* This is achieved by requiring that the <code>Collection</code> passed to
|
||||
* the {@link #CollectionCertStore(CertStoreParameters)
|
||||
* CollectionCertStore(CertStoreParameters)} constructor (via the
|
||||
* <code>CollectionCertStoreParameters</code> object) must have fail-fast
|
||||
* iterators. Simultaneous modifications to the <code>Collection</code> can thus be
|
||||
* detected and certificate or CRL retrieval can be retried. The fact that
|
||||
* <code>Certificate</code>s and <code>CRL</code>s must be thread-safe is also
|
||||
* essential.
|
||||
*
|
||||
* @see java.security.cert.CertStore
|
||||
*
|
||||
* @since 1.4
|
||||
* @author Steve Hanna
|
||||
*/
|
||||
public class CollectionCertStore extends CertStoreSpi {
|
||||
|
||||
private Collection<?> coll;
|
||||
|
||||
/**
|
||||
* Creates a <code>CertStore</code> with the specified parameters.
|
||||
* For this class, the parameters object must be an instance of
|
||||
* <code>CollectionCertStoreParameters</code>. The <code>Collection</code>
|
||||
* included in the <code>CollectionCertStoreParameters</code> object
|
||||
* must be thread-safe.
|
||||
*
|
||||
* @param params the algorithm parameters
|
||||
* @exception InvalidAlgorithmParameterException if params is not an
|
||||
* instance of <code>CollectionCertStoreParameters</code>
|
||||
*/
|
||||
public CollectionCertStore(CertStoreParameters params)
|
||||
throws InvalidAlgorithmParameterException
|
||||
{
|
||||
super(params);
|
||||
if (!(params instanceof CollectionCertStoreParameters))
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"parameters must be CollectionCertStoreParameters");
|
||||
coll = ((CollectionCertStoreParameters) params).getCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>Collection</code> of <code>Certificate</code>s that
|
||||
* match the specified selector. If no <code>Certificate</code>s
|
||||
* match the selector, an empty <code>Collection</code> will be returned.
|
||||
*
|
||||
* @param selector a <code>CertSelector</code> used to select which
|
||||
* <code>Certificate</code>s should be returned. Specify <code>null</code>
|
||||
* to return all <code>Certificate</code>s.
|
||||
* @return a <code>Collection</code> of <code>Certificate</code>s that
|
||||
* match the specified selector
|
||||
* @throws CertStoreException if an exception occurs
|
||||
*/
|
||||
@Override
|
||||
public Collection<Certificate> engineGetCertificates
|
||||
(CertSelector selector) throws CertStoreException {
|
||||
if (coll == null) {
|
||||
throw new CertStoreException("Collection is null");
|
||||
}
|
||||
// Tolerate a few ConcurrentModificationExceptions
|
||||
for (int c = 0; c < 10; c++) {
|
||||
try {
|
||||
HashSet<Certificate> result = new HashSet<>();
|
||||
if (selector != null) {
|
||||
for (Object o : coll) {
|
||||
if ((o instanceof Certificate) &&
|
||||
selector.match((Certificate) o))
|
||||
result.add((Certificate)o);
|
||||
}
|
||||
} else {
|
||||
for (Object o : coll) {
|
||||
if (o instanceof Certificate)
|
||||
result.add((Certificate)o);
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
} catch (ConcurrentModificationException e) { }
|
||||
}
|
||||
throw new ConcurrentModificationException("Too many "
|
||||
+ "ConcurrentModificationExceptions");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>Collection</code> of <code>CRL</code>s that
|
||||
* match the specified selector. If no <code>CRL</code>s
|
||||
* match the selector, an empty <code>Collection</code> will be returned.
|
||||
*
|
||||
* @param selector a <code>CRLSelector</code> used to select which
|
||||
* <code>CRL</code>s should be returned. Specify <code>null</code>
|
||||
* to return all <code>CRL</code>s.
|
||||
* @return a <code>Collection</code> of <code>CRL</code>s that
|
||||
* match the specified selector
|
||||
* @throws CertStoreException if an exception occurs
|
||||
*/
|
||||
@Override
|
||||
public Collection<CRL> engineGetCRLs(CRLSelector selector)
|
||||
throws CertStoreException
|
||||
{
|
||||
if (coll == null)
|
||||
throw new CertStoreException("Collection is null");
|
||||
|
||||
// Tolerate a few ConcurrentModificationExceptions
|
||||
for (int c = 0; c < 10; c++) {
|
||||
try {
|
||||
HashSet<CRL> result = new HashSet<>();
|
||||
if (selector != null) {
|
||||
for (Object o : coll) {
|
||||
if ((o instanceof CRL) && selector.match((CRL) o))
|
||||
result.add((CRL)o);
|
||||
}
|
||||
} else {
|
||||
for (Object o : coll) {
|
||||
if (o instanceof CRL)
|
||||
result.add((CRL)o);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} catch (ConcurrentModificationException e) { }
|
||||
}
|
||||
throw new ConcurrentModificationException("Too many "
|
||||
+ "ConcurrentModificationExceptions");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertPathValidatorException;
|
||||
import java.security.cert.PKIXCertPathChecker;
|
||||
import java.security.cert.PKIXReason;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import sun.security.util.Debug;
|
||||
import static sun.security.x509.PKIXExtensions.*;
|
||||
import sun.security.x509.NameConstraintsExtension;
|
||||
import sun.security.x509.X509CertImpl;
|
||||
|
||||
/**
|
||||
* ConstraintsChecker is a <code>PKIXCertPathChecker</code> that checks
|
||||
* constraints information on a PKIX certificate, namely basic constraints
|
||||
* and name constraints.
|
||||
*
|
||||
* @since 1.4
|
||||
* @author Yassir Elley
|
||||
*/
|
||||
class ConstraintsChecker extends PKIXCertPathChecker {
|
||||
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
/* length of cert path */
|
||||
private final int certPathLength;
|
||||
/* current maximum path length (as defined in PKIX) */
|
||||
private int maxPathLength;
|
||||
/* current index of cert */
|
||||
private int i;
|
||||
private NameConstraintsExtension prevNC;
|
||||
|
||||
private Set<String> supportedExts;
|
||||
|
||||
/**
|
||||
* Creates a ConstraintsChecker.
|
||||
*
|
||||
* @param certPathLength the length of the certification path
|
||||
*/
|
||||
ConstraintsChecker(int certPathLength) {
|
||||
this.certPathLength = certPathLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(boolean forward) throws CertPathValidatorException {
|
||||
if (!forward) {
|
||||
i = 0;
|
||||
maxPathLength = certPathLength;
|
||||
prevNC = null;
|
||||
} else {
|
||||
throw new CertPathValidatorException
|
||||
("forward checking not supported");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForwardCheckingSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedExtensions() {
|
||||
if (supportedExts == null) {
|
||||
supportedExts = new HashSet<String>(2);
|
||||
supportedExts.add(BasicConstraints_Id.toString());
|
||||
supportedExts.add(NameConstraints_Id.toString());
|
||||
supportedExts = Collections.unmodifiableSet(supportedExts);
|
||||
}
|
||||
return supportedExts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the basic constraints and name constraints
|
||||
* checks on the certificate using its internal state.
|
||||
*
|
||||
* @param cert the <code>Certificate</code> to be checked
|
||||
* @param unresCritExts a <code>Collection</code> of OID strings
|
||||
* representing the current set of unresolved critical extensions
|
||||
* @throws CertPathValidatorException if the specified certificate
|
||||
* does not pass the check
|
||||
*/
|
||||
@Override
|
||||
public void check(Certificate cert, Collection<String> unresCritExts)
|
||||
throws CertPathValidatorException
|
||||
{
|
||||
X509Certificate currCert = (X509Certificate)cert;
|
||||
|
||||
i++;
|
||||
// MUST run NC check second, since it depends on BC check to
|
||||
// update remainingCerts
|
||||
checkBasicConstraints(currCert);
|
||||
verifyNameConstraints(currCert);
|
||||
|
||||
if (unresCritExts != null && !unresCritExts.isEmpty()) {
|
||||
unresCritExts.remove(BasicConstraints_Id.toString());
|
||||
unresCritExts.remove(NameConstraints_Id.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to check the name constraints against a cert
|
||||
*/
|
||||
private void verifyNameConstraints(X509Certificate currCert)
|
||||
throws CertPathValidatorException
|
||||
{
|
||||
String msg = "name constraints";
|
||||
if (debug != null) {
|
||||
debug.println("---checking " + msg + "...");
|
||||
}
|
||||
|
||||
// check name constraints only if there is a previous name constraint
|
||||
// and either the currCert is the final cert or the currCert is not
|
||||
// self-issued
|
||||
if (prevNC != null && ((i == certPathLength) ||
|
||||
!X509CertImpl.isSelfIssued(currCert))) {
|
||||
if (debug != null) {
|
||||
debug.println("prevNC = " + prevNC +
|
||||
", currDN = " + currCert.getSubjectX500Principal());
|
||||
}
|
||||
|
||||
try {
|
||||
if (!prevNC.verify(currCert)) {
|
||||
throw new CertPathValidatorException(msg + " check failed",
|
||||
null, null, -1, PKIXReason.INVALID_NAME);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new CertPathValidatorException(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
// merge name constraints regardless of whether cert is self-issued
|
||||
prevNC = mergeNameConstraints(currCert, prevNC);
|
||||
|
||||
if (debug != null)
|
||||
debug.println(msg + " verified.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to fold sets of name constraints together
|
||||
*/
|
||||
static NameConstraintsExtension mergeNameConstraints(
|
||||
X509Certificate currCert, NameConstraintsExtension prevNC)
|
||||
throws CertPathValidatorException
|
||||
{
|
||||
X509CertImpl currCertImpl;
|
||||
try {
|
||||
currCertImpl = X509CertImpl.toImpl(currCert);
|
||||
} catch (CertificateException ce) {
|
||||
throw new CertPathValidatorException(ce);
|
||||
}
|
||||
|
||||
NameConstraintsExtension newConstraints =
|
||||
currCertImpl.getNameConstraintsExtension();
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("prevNC = " + prevNC +
|
||||
", newNC = " + String.valueOf(newConstraints));
|
||||
}
|
||||
|
||||
// if there are no previous name constraints, we just return the
|
||||
// new name constraints.
|
||||
if (prevNC == null) {
|
||||
if (debug != null) {
|
||||
debug.println("mergedNC = " + String.valueOf(newConstraints));
|
||||
}
|
||||
if (newConstraints == null) {
|
||||
return newConstraints;
|
||||
} else {
|
||||
// Make sure we do a clone here, because we're probably
|
||||
// going to modify this object later and we don't want to
|
||||
// be sharing it with a Certificate object!
|
||||
return (NameConstraintsExtension)newConstraints.clone();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
// after merge, prevNC should contain the merged constraints
|
||||
prevNC.merge(newConstraints);
|
||||
} catch (IOException ioe) {
|
||||
throw new CertPathValidatorException(ioe);
|
||||
}
|
||||
if (debug != null) {
|
||||
debug.println("mergedNC = " + prevNC);
|
||||
}
|
||||
return prevNC;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to check that a given cert meets basic constraints.
|
||||
*/
|
||||
private void checkBasicConstraints(X509Certificate currCert)
|
||||
throws CertPathValidatorException
|
||||
{
|
||||
String msg = "basic constraints";
|
||||
if (debug != null) {
|
||||
debug.println("---checking " + msg + "...");
|
||||
debug.println("i = " + i +
|
||||
", maxPathLength = " + maxPathLength);
|
||||
}
|
||||
|
||||
/* check if intermediate cert */
|
||||
if (i < certPathLength) {
|
||||
// RFC5280: If certificate i is a version 3 certificate, verify
|
||||
// that the basicConstraints extension is present and that cA is
|
||||
// set to TRUE. (If certificate i is a version 1 or version 2
|
||||
// certificate, then the application MUST either verify that
|
||||
// certificate i is a CA certificate through out-of-band means
|
||||
// or reject the certificate. Conforming implementations may
|
||||
// choose to reject all version 1 and version 2 intermediate
|
||||
// certificates.)
|
||||
//
|
||||
// We choose to reject all version 1 and version 2 intermediate
|
||||
// certificates except that it is self issued by the trust
|
||||
// anchor in order to support key rollover or changes in
|
||||
// certificate policies.
|
||||
int pathLenConstraint = -1;
|
||||
if (currCert.getVersion() < 3) { // version 1 or version 2
|
||||
if (i == 1) { // issued by a trust anchor
|
||||
if (X509CertImpl.isSelfIssued(currCert)) {
|
||||
pathLenConstraint = Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pathLenConstraint = currCert.getBasicConstraints();
|
||||
}
|
||||
|
||||
if (pathLenConstraint == -1) {
|
||||
throw new CertPathValidatorException
|
||||
(msg + " check failed: this is not a CA certificate",
|
||||
null, null, -1, PKIXReason.NOT_CA_CERT);
|
||||
}
|
||||
|
||||
if (!X509CertImpl.isSelfIssued(currCert)) {
|
||||
if (maxPathLength <= 0) {
|
||||
throw new CertPathValidatorException
|
||||
(msg + " check failed: pathLenConstraint violated - "
|
||||
+ "this cert must be the last cert in the "
|
||||
+ "certification path", null, null, -1,
|
||||
PKIXReason.PATH_TOO_LONG);
|
||||
}
|
||||
maxPathLength--;
|
||||
}
|
||||
if (pathLenConstraint < maxPathLength)
|
||||
maxPathLength = pathLenConstraint;
|
||||
}
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("after processing, maxPathLength = " + maxPathLength);
|
||||
debug.println(msg + " verified.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the specified maxPathLength with the pathLenConstraint
|
||||
* obtained from the certificate.
|
||||
*
|
||||
* @param cert the <code>X509Certificate</code>
|
||||
* @param maxPathLength the previous maximum path length
|
||||
* @return the new maximum path length constraint (-1 means no more
|
||||
* certificates can follow, Integer.MAX_VALUE means path length is
|
||||
* unconstrained)
|
||||
*/
|
||||
static int mergeBasicConstraints(X509Certificate cert, int maxPathLength) {
|
||||
|
||||
int pathLenConstraint = cert.getBasicConstraints();
|
||||
|
||||
if (!X509CertImpl.isSelfIssued(cert)) {
|
||||
maxPathLength--;
|
||||
}
|
||||
|
||||
if (pathLenConstraint < maxPathLength) {
|
||||
maxPathLength = pathLenConstraint;
|
||||
}
|
||||
|
||||
return maxPathLength;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,804 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URI;
|
||||
import java.security.*;
|
||||
import java.security.cert.*;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
import java.util.*;
|
||||
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.validator.Validator;
|
||||
import static sun.security.x509.PKIXExtensions.*;
|
||||
import sun.security.x509.*;
|
||||
|
||||
/**
|
||||
* Class to obtain CRLs via the CRLDistributionPoints extension.
|
||||
* Note that the functionality of this class must be explicitly enabled
|
||||
* via a system property, see the USE_CRLDP variable below.
|
||||
*
|
||||
* This class uses the URICertStore class to fetch CRLs. The URICertStore
|
||||
* class also implements CRL caching: see the class description for more
|
||||
* information.
|
||||
*
|
||||
* @author Andreas Sterbenz
|
||||
* @author Sean Mullan
|
||||
* @since 1.4.2
|
||||
*/
|
||||
public class DistributionPointFetcher {
|
||||
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
|
||||
private static final boolean[] ALL_REASONS =
|
||||
{true, true, true, true, true, true, true, true, true};
|
||||
|
||||
/**
|
||||
* Private instantiation only.
|
||||
*/
|
||||
private DistributionPointFetcher() {}
|
||||
|
||||
/**
|
||||
* Return the X509CRLs matching this selector. The selector must be
|
||||
* an X509CRLSelector with certificateChecking set.
|
||||
*/
|
||||
public static Collection<X509CRL> getCRLs(X509CRLSelector selector,
|
||||
boolean signFlag, PublicKey prevKey, String provider,
|
||||
List<CertStore> certStores, boolean[] reasonsMask,
|
||||
Set<TrustAnchor> trustAnchors, Date validity, String variant)
|
||||
throws CertStoreException
|
||||
{
|
||||
return getCRLs(selector, signFlag, prevKey, null, provider, certStores,
|
||||
reasonsMask, trustAnchors, validity, variant, null);
|
||||
}
|
||||
/**
|
||||
* Return the X509CRLs matching this selector. The selector must be
|
||||
* an X509CRLSelector with certificateChecking set.
|
||||
*/
|
||||
// Called by com.sun.deploy.security.RevocationChecker
|
||||
public static Collection<X509CRL> getCRLs(X509CRLSelector selector,
|
||||
boolean signFlag,
|
||||
PublicKey prevKey,
|
||||
String provider,
|
||||
List<CertStore> certStores,
|
||||
boolean[] reasonsMask,
|
||||
Set<TrustAnchor> trustAnchors,
|
||||
Date validity)
|
||||
throws CertStoreException
|
||||
{
|
||||
if (trustAnchors.isEmpty()) {
|
||||
throw new CertStoreException(
|
||||
"at least one TrustAnchor must be specified");
|
||||
}
|
||||
TrustAnchor anchor = trustAnchors.iterator().next();
|
||||
return getCRLs(selector, signFlag, prevKey, null, provider, certStores,
|
||||
reasonsMask, trustAnchors, validity,
|
||||
Validator.VAR_PLUGIN_CODE_SIGNING, anchor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the X509CRLs matching this selector. The selector must be
|
||||
* an X509CRLSelector with certificateChecking set.
|
||||
*/
|
||||
public static Collection<X509CRL> getCRLs(X509CRLSelector selector,
|
||||
boolean signFlag,
|
||||
PublicKey prevKey,
|
||||
X509Certificate prevCert,
|
||||
String provider,
|
||||
List<CertStore> certStores,
|
||||
boolean[] reasonsMask,
|
||||
Set<TrustAnchor> trustAnchors,
|
||||
Date validity,
|
||||
String variant,
|
||||
TrustAnchor anchor)
|
||||
throws CertStoreException
|
||||
{
|
||||
X509Certificate cert = selector.getCertificateChecking();
|
||||
if (cert == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
try {
|
||||
X509CertImpl certImpl = X509CertImpl.toImpl(cert);
|
||||
if (debug != null) {
|
||||
debug.println("DistributionPointFetcher.getCRLs: Checking "
|
||||
+ "CRLDPs for " + certImpl.getSubjectX500Principal());
|
||||
}
|
||||
CRLDistributionPointsExtension ext =
|
||||
certImpl.getCRLDistributionPointsExtension();
|
||||
if (ext == null) {
|
||||
if (debug != null) {
|
||||
debug.println("No CRLDP ext");
|
||||
}
|
||||
return Collections.emptySet();
|
||||
}
|
||||
List<DistributionPoint> points =
|
||||
ext.get(CRLDistributionPointsExtension.POINTS);
|
||||
Set<X509CRL> results = new HashSet<>();
|
||||
for (Iterator<DistributionPoint> t = points.iterator();
|
||||
t.hasNext() && !Arrays.equals(reasonsMask, ALL_REASONS); ) {
|
||||
DistributionPoint point = t.next();
|
||||
Collection<X509CRL> crls = getCRLs(selector, certImpl,
|
||||
point, reasonsMask, signFlag, prevKey, prevCert, provider,
|
||||
certStores, trustAnchors, validity, variant, anchor);
|
||||
results.addAll(crls);
|
||||
}
|
||||
if (debug != null) {
|
||||
debug.println("Returning " + results.size() + " CRLs");
|
||||
}
|
||||
return results;
|
||||
} catch (CertificateException | IOException e) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Download CRLs from the given distribution point, verify and return them.
|
||||
* See the top of the class for current limitations.
|
||||
*
|
||||
* @throws CertStoreException if there is an error retrieving the CRLs
|
||||
* from one of the GeneralNames and no other CRLs are retrieved from
|
||||
* the other GeneralNames. If more than one GeneralName throws an
|
||||
* exception then the one from the last GeneralName is thrown.
|
||||
*/
|
||||
private static Collection<X509CRL> getCRLs(X509CRLSelector selector,
|
||||
X509CertImpl certImpl, DistributionPoint point, boolean[] reasonsMask,
|
||||
boolean signFlag, PublicKey prevKey, X509Certificate prevCert,
|
||||
String provider, List<CertStore> certStores,
|
||||
Set<TrustAnchor> trustAnchors, Date validity, String variant,
|
||||
TrustAnchor anchor)
|
||||
throws CertStoreException {
|
||||
|
||||
// check for full name
|
||||
GeneralNames fullName = point.getFullName();
|
||||
if (fullName == null) {
|
||||
// check for relative name
|
||||
RDN relativeName = point.getRelativeName();
|
||||
if (relativeName == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
try {
|
||||
GeneralNames crlIssuers = point.getCRLIssuer();
|
||||
if (crlIssuers == null) {
|
||||
fullName = getFullNames
|
||||
((X500Name) certImpl.getIssuerDN(), relativeName);
|
||||
} else {
|
||||
// should only be one CRL Issuer
|
||||
if (crlIssuers.size() != 1) {
|
||||
return Collections.emptySet();
|
||||
} else {
|
||||
fullName = getFullNames
|
||||
((X500Name) crlIssuers.get(0).getName(), relativeName);
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
Collection<X509CRL> possibleCRLs = new ArrayList<>();
|
||||
CertStoreException savedCSE = null;
|
||||
for (Iterator<GeneralName> t = fullName.iterator(); t.hasNext(); ) {
|
||||
try {
|
||||
GeneralName name = t.next();
|
||||
if (name.getType() == GeneralNameInterface.NAME_DIRECTORY) {
|
||||
X500Name x500Name = (X500Name) name.getName();
|
||||
possibleCRLs.addAll(
|
||||
getCRLs(x500Name, certImpl.getIssuerX500Principal(),
|
||||
certStores));
|
||||
} else if (name.getType() == GeneralNameInterface.NAME_URI) {
|
||||
URIName uriName = (URIName)name.getName();
|
||||
X509CRL crl = getCRL(uriName);
|
||||
if (crl != null) {
|
||||
possibleCRLs.add(crl);
|
||||
}
|
||||
}
|
||||
} catch (CertStoreException cse) {
|
||||
savedCSE = cse;
|
||||
}
|
||||
}
|
||||
// only throw CertStoreException if no CRLs are retrieved
|
||||
if (possibleCRLs.isEmpty() && savedCSE != null) {
|
||||
throw savedCSE;
|
||||
}
|
||||
|
||||
Collection<X509CRL> crls = new ArrayList<>(2);
|
||||
for (X509CRL crl : possibleCRLs) {
|
||||
try {
|
||||
// make sure issuer is not set
|
||||
// we check the issuer in verifyCRLs method
|
||||
selector.setIssuerNames(null);
|
||||
if (selector.match(crl) && verifyCRL(certImpl, point, crl,
|
||||
reasonsMask, signFlag, prevKey, prevCert, provider,
|
||||
trustAnchors, certStores, validity, variant, anchor)) {
|
||||
crls.add(crl);
|
||||
}
|
||||
} catch (IOException | CRLException e) {
|
||||
// don't add the CRL
|
||||
if (debug != null) {
|
||||
debug.println("Exception verifying CRL: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return crls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Download CRL from given URI.
|
||||
*/
|
||||
private static X509CRL getCRL(URIName name) throws CertStoreException {
|
||||
URI uri = name.getURI();
|
||||
if (debug != null) {
|
||||
debug.println("Trying to fetch CRL from DP " + uri);
|
||||
}
|
||||
CertStore ucs = null;
|
||||
try {
|
||||
ucs = URICertStore.getInstance
|
||||
(new URICertStore.URICertStoreParameters(uri));
|
||||
} catch (InvalidAlgorithmParameterException |
|
||||
NoSuchAlgorithmException e) {
|
||||
if (debug != null) {
|
||||
debug.println("Can't create URICertStore: " + e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Collection<? extends CRL> crls = ucs.getCRLs(null);
|
||||
if (crls.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return (X509CRL) crls.iterator().next();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch CRLs from certStores.
|
||||
*
|
||||
* @throws CertStoreException if there is an error retrieving the CRLs from
|
||||
* one of the CertStores and no other CRLs are retrieved from
|
||||
* the other CertStores. If more than one CertStore throws an
|
||||
* exception then the one from the last CertStore is thrown.
|
||||
*/
|
||||
private static Collection<X509CRL> getCRLs(X500Name name,
|
||||
X500Principal certIssuer,
|
||||
List<CertStore> certStores)
|
||||
throws CertStoreException
|
||||
{
|
||||
if (debug != null) {
|
||||
debug.println("Trying to fetch CRL from DP " + name);
|
||||
}
|
||||
X509CRLSelector xcs = new X509CRLSelector();
|
||||
xcs.addIssuer(name.asX500Principal());
|
||||
xcs.addIssuer(certIssuer);
|
||||
Collection<X509CRL> crls = new ArrayList<>();
|
||||
CertStoreException savedCSE = null;
|
||||
for (CertStore store : certStores) {
|
||||
try {
|
||||
for (CRL crl : store.getCRLs(xcs)) {
|
||||
crls.add((X509CRL)crl);
|
||||
}
|
||||
} catch (CertStoreException cse) {
|
||||
if (debug != null) {
|
||||
debug.println("Exception while retrieving " +
|
||||
"CRLs: " + cse);
|
||||
cse.printStackTrace();
|
||||
}
|
||||
savedCSE = new PKIX.CertStoreTypeException(store.getType(),cse);
|
||||
}
|
||||
}
|
||||
// only throw CertStoreException if no CRLs are retrieved
|
||||
if (crls.isEmpty() && savedCSE != null) {
|
||||
throw savedCSE;
|
||||
} else {
|
||||
return crls;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies a CRL for the given certificate's Distribution Point to
|
||||
* ensure it is appropriate for checking the revocation status.
|
||||
*
|
||||
* @param certImpl the certificate whose revocation status is being checked
|
||||
* @param point one of the distribution points of the certificate
|
||||
* @param crl the CRL
|
||||
* @param reasonsMask the interim reasons mask
|
||||
* @param signFlag true if prevKey can be used to verify the CRL
|
||||
* @param prevKey the public key that verifies the certificate's signature
|
||||
* @param prevCert the certificate whose public key verifies
|
||||
* {@code certImpl}'s signature
|
||||
* @param provider the Signature provider to use
|
||||
* @param trustAnchors a {@code Set} of {@code TrustAnchor}s
|
||||
* @param certStores a {@code List} of {@code CertStore}s to be used in
|
||||
* finding certificates and CRLs
|
||||
* @param validity the time for which the validity of the CRL issuer's
|
||||
* certification path should be determined
|
||||
* @return true if ok, false if not
|
||||
*/
|
||||
static boolean verifyCRL(X509CertImpl certImpl, DistributionPoint point,
|
||||
X509CRL crl, boolean[] reasonsMask, boolean signFlag,
|
||||
PublicKey prevKey, X509Certificate prevCert, String provider,
|
||||
Set<TrustAnchor> trustAnchors, List<CertStore> certStores,
|
||||
Date validity, String variant, TrustAnchor anchor)
|
||||
throws CRLException, IOException {
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("DistributionPointFetcher.verifyCRL: " +
|
||||
"checking revocation status for" +
|
||||
"\n SN: " + Debug.toHexString(certImpl.getSerialNumber()) +
|
||||
"\n Subject: " + certImpl.getSubjectX500Principal() +
|
||||
"\n Issuer: " + certImpl.getIssuerX500Principal());
|
||||
}
|
||||
|
||||
boolean indirectCRL = false;
|
||||
X509CRLImpl crlImpl = X509CRLImpl.toImpl(crl);
|
||||
IssuingDistributionPointExtension idpExt =
|
||||
crlImpl.getIssuingDistributionPointExtension();
|
||||
X500Name certIssuer = (X500Name) certImpl.getIssuerDN();
|
||||
X500Name crlIssuer = (X500Name) crlImpl.getIssuerDN();
|
||||
|
||||
// if crlIssuer is set, verify that it matches the issuer of the
|
||||
// CRL and the CRL contains an IDP extension with the indirectCRL
|
||||
// boolean asserted. Otherwise, verify that the CRL issuer matches the
|
||||
// certificate issuer.
|
||||
GeneralNames pointCrlIssuers = point.getCRLIssuer();
|
||||
X500Name pointCrlIssuer = null;
|
||||
if (pointCrlIssuers != null) {
|
||||
if (idpExt == null ||
|
||||
((Boolean) idpExt.get
|
||||
(IssuingDistributionPointExtension.INDIRECT_CRL)).equals
|
||||
(Boolean.FALSE)) {
|
||||
return false;
|
||||
}
|
||||
boolean match = false;
|
||||
for (Iterator<GeneralName> t = pointCrlIssuers.iterator();
|
||||
!match && t.hasNext(); ) {
|
||||
GeneralNameInterface name = t.next().getName();
|
||||
if (crlIssuer.equals(name) == true) {
|
||||
pointCrlIssuer = (X500Name) name;
|
||||
match = true;
|
||||
}
|
||||
}
|
||||
if (match == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// we accept the case that a CRL issuer provide status
|
||||
// information for itself.
|
||||
if (issues(certImpl, crlImpl, provider)) {
|
||||
// reset the public key used to verify the CRL's signature
|
||||
prevKey = certImpl.getPublicKey();
|
||||
} else {
|
||||
indirectCRL = true;
|
||||
}
|
||||
} else if (crlIssuer.equals(certIssuer) == false) {
|
||||
if (debug != null) {
|
||||
debug.println("crl issuer does not equal cert issuer.\n" +
|
||||
"crl issuer: " + crlIssuer + "\n" +
|
||||
"cert issuer: " + certIssuer);
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
// in case of self-issued indirect CRL issuer.
|
||||
KeyIdentifier certAKID = certImpl.getAuthKeyId();
|
||||
KeyIdentifier crlAKID = crlImpl.getAuthKeyId();
|
||||
|
||||
if (certAKID == null || crlAKID == null) {
|
||||
// cannot recognize indirect CRL without AKID
|
||||
|
||||
// we accept the case that a CRL issuer provide status
|
||||
// information for itself.
|
||||
if (issues(certImpl, crlImpl, provider)) {
|
||||
// reset the public key used to verify the CRL's signature
|
||||
prevKey = certImpl.getPublicKey();
|
||||
}
|
||||
} else if (!certAKID.equals(crlAKID)) {
|
||||
// we accept the case that a CRL issuer provide status
|
||||
// information for itself.
|
||||
if (issues(certImpl, crlImpl, provider)) {
|
||||
// reset the public key used to verify the CRL's signature
|
||||
prevKey = certImpl.getPublicKey();
|
||||
} else {
|
||||
indirectCRL = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!indirectCRL && !signFlag) {
|
||||
// cert's key cannot be used to verify the CRL
|
||||
return false;
|
||||
}
|
||||
|
||||
if (idpExt != null) {
|
||||
DistributionPointName idpPoint = (DistributionPointName)
|
||||
idpExt.get(IssuingDistributionPointExtension.POINT);
|
||||
if (idpPoint != null) {
|
||||
GeneralNames idpNames = idpPoint.getFullName();
|
||||
if (idpNames == null) {
|
||||
RDN relativeName = idpPoint.getRelativeName();
|
||||
if (relativeName == null) {
|
||||
if (debug != null) {
|
||||
debug.println("IDP must be relative or full DN");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (debug != null) {
|
||||
debug.println("IDP relativeName:" + relativeName);
|
||||
}
|
||||
idpNames = getFullNames(crlIssuer, relativeName);
|
||||
}
|
||||
// if the DP name is present in the IDP CRL extension and the
|
||||
// DP field is present in the DP, then verify that one of the
|
||||
// names in the IDP matches one of the names in the DP
|
||||
if (point.getFullName() != null ||
|
||||
point.getRelativeName() != null) {
|
||||
GeneralNames pointNames = point.getFullName();
|
||||
if (pointNames == null) {
|
||||
RDN relativeName = point.getRelativeName();
|
||||
if (relativeName == null) {
|
||||
if (debug != null) {
|
||||
debug.println("DP must be relative or full DN");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (debug != null) {
|
||||
debug.println("DP relativeName:" + relativeName);
|
||||
}
|
||||
if (indirectCRL) {
|
||||
if (pointCrlIssuers.size() != 1) {
|
||||
// RFC 5280: there must be only 1 CRL issuer
|
||||
// name when relativeName is present
|
||||
if (debug != null) {
|
||||
debug.println("must only be one CRL " +
|
||||
"issuer when relative name present");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
pointNames = getFullNames
|
||||
(pointCrlIssuer, relativeName);
|
||||
} else {
|
||||
pointNames = getFullNames(certIssuer, relativeName);
|
||||
}
|
||||
}
|
||||
boolean match = false;
|
||||
for (Iterator<GeneralName> i = idpNames.iterator();
|
||||
!match && i.hasNext(); ) {
|
||||
GeneralNameInterface idpName = i.next().getName();
|
||||
if (debug != null) {
|
||||
debug.println("idpName: " + idpName);
|
||||
}
|
||||
for (Iterator<GeneralName> p = pointNames.iterator();
|
||||
!match && p.hasNext(); ) {
|
||||
GeneralNameInterface pointName = p.next().getName();
|
||||
if (debug != null) {
|
||||
debug.println("pointName: " + pointName);
|
||||
}
|
||||
match = idpName.equals(pointName);
|
||||
}
|
||||
}
|
||||
if (!match) {
|
||||
if (debug != null) {
|
||||
debug.println("IDP name does not match DP name");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// if the DP name is present in the IDP CRL extension and the
|
||||
// DP field is absent from the DP, then verify that one of the
|
||||
// names in the IDP matches one of the names in the crlIssuer
|
||||
// field of the DP
|
||||
} else {
|
||||
// verify that one of the names in the IDP matches one of
|
||||
// the names in the cRLIssuer of the cert's DP
|
||||
boolean match = false;
|
||||
for (Iterator<GeneralName> t = pointCrlIssuers.iterator();
|
||||
!match && t.hasNext(); ) {
|
||||
GeneralNameInterface crlIssuerName = t.next().getName();
|
||||
for (Iterator<GeneralName> i = idpNames.iterator();
|
||||
!match && i.hasNext(); ) {
|
||||
GeneralNameInterface idpName = i.next().getName();
|
||||
match = crlIssuerName.equals(idpName);
|
||||
}
|
||||
}
|
||||
if (!match) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if the onlyContainsUserCerts boolean is asserted, verify that the
|
||||
// cert is not a CA cert
|
||||
Boolean b = (Boolean)
|
||||
idpExt.get(IssuingDistributionPointExtension.ONLY_USER_CERTS);
|
||||
if (b.equals(Boolean.TRUE) && certImpl.getBasicConstraints() != -1) {
|
||||
if (debug != null) {
|
||||
debug.println("cert must be a EE cert");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the onlyContainsCACerts boolean is asserted, verify that the
|
||||
// cert is a CA cert
|
||||
b = (Boolean)
|
||||
idpExt.get(IssuingDistributionPointExtension.ONLY_CA_CERTS);
|
||||
if (b.equals(Boolean.TRUE) && certImpl.getBasicConstraints() == -1) {
|
||||
if (debug != null) {
|
||||
debug.println("cert must be a CA cert");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// verify that the onlyContainsAttributeCerts boolean is not
|
||||
// asserted
|
||||
b = (Boolean) idpExt.get
|
||||
(IssuingDistributionPointExtension.ONLY_ATTRIBUTE_CERTS);
|
||||
if (b.equals(Boolean.TRUE)) {
|
||||
if (debug != null) {
|
||||
debug.println("cert must not be an AA cert");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// compute interim reasons mask
|
||||
boolean[] interimReasonsMask = new boolean[9];
|
||||
ReasonFlags reasons = null;
|
||||
if (idpExt != null) {
|
||||
reasons = (ReasonFlags)
|
||||
idpExt.get(IssuingDistributionPointExtension.REASONS);
|
||||
}
|
||||
|
||||
boolean[] pointReasonFlags = point.getReasonFlags();
|
||||
if (reasons != null) {
|
||||
if (pointReasonFlags != null) {
|
||||
// set interim reasons mask to the intersection of
|
||||
// reasons in the DP and onlySomeReasons in the IDP
|
||||
boolean[] idpReasonFlags = reasons.getFlags();
|
||||
for (int i = 0; i < interimReasonsMask.length; i++) {
|
||||
interimReasonsMask[i] =
|
||||
(i < idpReasonFlags.length && idpReasonFlags[i]) &&
|
||||
(i < pointReasonFlags.length && pointReasonFlags[i]);
|
||||
}
|
||||
} else {
|
||||
// set interim reasons mask to the value of
|
||||
// onlySomeReasons in the IDP (and clone it since we may
|
||||
// modify it)
|
||||
interimReasonsMask = reasons.getFlags().clone();
|
||||
}
|
||||
} else if (idpExt == null || reasons == null) {
|
||||
if (pointReasonFlags != null) {
|
||||
// set interim reasons mask to the value of DP reasons
|
||||
interimReasonsMask = pointReasonFlags.clone();
|
||||
} else {
|
||||
// set interim reasons mask to the special value all-reasons
|
||||
Arrays.fill(interimReasonsMask, true);
|
||||
}
|
||||
}
|
||||
|
||||
// verify that interim reasons mask includes one or more reasons
|
||||
// not included in the reasons mask
|
||||
boolean oneOrMore = false;
|
||||
for (int i = 0; i < interimReasonsMask.length && !oneOrMore; i++) {
|
||||
if (interimReasonsMask[i] &&
|
||||
!(i < reasonsMask.length && reasonsMask[i]))
|
||||
{
|
||||
oneOrMore = true;
|
||||
}
|
||||
}
|
||||
if (!oneOrMore) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Obtain and validate the certification path for the complete
|
||||
// CRL issuer (if indirect CRL). If a key usage extension is present
|
||||
// in the CRL issuer's certificate, verify that the cRLSign bit is set.
|
||||
if (indirectCRL) {
|
||||
X509CertSelector certSel = new X509CertSelector();
|
||||
certSel.setSubject(crlIssuer.asX500Principal());
|
||||
boolean[] crlSign = {false,false,false,false,false,false,true};
|
||||
certSel.setKeyUsage(crlSign);
|
||||
|
||||
// Currently by default, forward builder does not enable
|
||||
// subject/authority key identifier identifying for target
|
||||
// certificate, instead, it only compares the CRL issuer and
|
||||
// the target certificate subject. If the certificate of the
|
||||
// delegated CRL issuer is a self-issued certificate, the
|
||||
// builder is unable to find the proper CRL issuer by issuer
|
||||
// name only, there is a potential dead loop on finding the
|
||||
// proper issuer. It is of great help to narrow the target
|
||||
// scope down to aware of authority key identifiers in the
|
||||
// selector, for the purposes of breaking the dead loop.
|
||||
AuthorityKeyIdentifierExtension akidext =
|
||||
crlImpl.getAuthKeyIdExtension();
|
||||
if (akidext != null) {
|
||||
byte[] kid = akidext.getEncodedKeyIdentifier();
|
||||
if (kid != null) {
|
||||
certSel.setSubjectKeyIdentifier(kid);
|
||||
}
|
||||
|
||||
SerialNumber asn = (SerialNumber)akidext.get(
|
||||
AuthorityKeyIdentifierExtension.SERIAL_NUMBER);
|
||||
if (asn != null) {
|
||||
certSel.setSerialNumber(asn.getNumber());
|
||||
}
|
||||
// the subject criterion will be set by builder automatically.
|
||||
}
|
||||
|
||||
// By now, we have validated the previous certificate, so we can
|
||||
// trust it during the validation of the CRL issuer.
|
||||
// In addition to the performance improvement, another benefit is to
|
||||
// break the dead loop while looking for the issuer back and forth
|
||||
// between the delegated self-issued certificate and its issuer.
|
||||
Set<TrustAnchor> newTrustAnchors = new HashSet<>(trustAnchors);
|
||||
|
||||
if (prevKey != null) {
|
||||
// Add the previous certificate as a trust anchor.
|
||||
// If prevCert is not null, we want to construct a TrustAnchor
|
||||
// using the cert object because when the certpath for the CRL
|
||||
// is built later, the CertSelector will make comparisons with
|
||||
// the TrustAnchor's trustedCert member rather than its pubKey.
|
||||
TrustAnchor temporary;
|
||||
if (prevCert != null) {
|
||||
temporary = new TrustAnchor(prevCert, null);
|
||||
} else {
|
||||
X500Principal principal = certImpl.getIssuerX500Principal();
|
||||
temporary = new TrustAnchor(principal, prevKey, null);
|
||||
}
|
||||
newTrustAnchors.add(temporary);
|
||||
}
|
||||
|
||||
PKIXBuilderParameters params = null;
|
||||
try {
|
||||
params = new PKIXBuilderParameters(newTrustAnchors, certSel);
|
||||
} catch (InvalidAlgorithmParameterException iape) {
|
||||
throw new CRLException(iape);
|
||||
}
|
||||
params.setCertStores(certStores);
|
||||
params.setSigProvider(provider);
|
||||
params.setDate(validity);
|
||||
try {
|
||||
CertPathBuilder builder = CertPathBuilder.getInstance("PKIX");
|
||||
PKIXCertPathBuilderResult result =
|
||||
(PKIXCertPathBuilderResult) builder.build(params);
|
||||
prevKey = result.getPublicKey();
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new CRLException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// check the crl signature algorithm
|
||||
try {
|
||||
AlgorithmChecker.check(prevKey, crlImpl.getSigAlgId(),
|
||||
variant, anchor);
|
||||
} catch (CertPathValidatorException cpve) {
|
||||
if (debug != null) {
|
||||
debug.println("CRL signature algorithm check failed: " + cpve);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// validate the signature on the CRL
|
||||
try {
|
||||
crl.verify(prevKey, provider);
|
||||
} catch (GeneralSecurityException e) {
|
||||
if (debug != null) {
|
||||
debug.println("CRL signature failed to verify");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// reject CRL if any unresolved critical extensions remain in the CRL.
|
||||
Set<String> unresCritExts = crl.getCriticalExtensionOIDs();
|
||||
// remove any that we have processed
|
||||
if (unresCritExts != null) {
|
||||
unresCritExts.remove(IssuingDistributionPoint_Id.toString());
|
||||
if (!unresCritExts.isEmpty()) {
|
||||
if (debug != null) {
|
||||
debug.println("Unrecognized critical extension(s) in CRL: "
|
||||
+ unresCritExts);
|
||||
for (String ext : unresCritExts) {
|
||||
debug.println(ext);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// update reasonsMask
|
||||
for (int i = 0; i < reasonsMask.length; i++) {
|
||||
reasonsMask[i] = reasonsMask[i] ||
|
||||
(i < interimReasonsMask.length && interimReasonsMask[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append relative name to the issuer name and return a new
|
||||
* GeneralNames object.
|
||||
*/
|
||||
private static GeneralNames getFullNames(X500Name issuer, RDN rdn)
|
||||
throws IOException
|
||||
{
|
||||
List<RDN> rdns = new ArrayList<>(issuer.rdns());
|
||||
rdns.add(rdn);
|
||||
X500Name fullName = new X500Name(rdns.toArray(new RDN[0]));
|
||||
GeneralNames fullNames = new GeneralNames();
|
||||
fullNames.add(new GeneralName(fullName));
|
||||
return fullNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies whether a CRL is issued by a certain certificate
|
||||
*
|
||||
* @param cert the certificate
|
||||
* @param crl the CRL to be verified
|
||||
* @param provider the name of the signature provider
|
||||
*/
|
||||
private static boolean issues(X509CertImpl cert, X509CRLImpl crl,
|
||||
String provider) throws IOException
|
||||
{
|
||||
boolean matched = false;
|
||||
|
||||
AdaptableX509CertSelector issuerSelector =
|
||||
new AdaptableX509CertSelector();
|
||||
|
||||
// check certificate's key usage
|
||||
boolean[] usages = cert.getKeyUsage();
|
||||
if (usages != null) {
|
||||
usages[6] = true; // cRLSign
|
||||
issuerSelector.setKeyUsage(usages);
|
||||
}
|
||||
|
||||
// check certificate's subject
|
||||
X500Principal crlIssuer = crl.getIssuerX500Principal();
|
||||
issuerSelector.setSubject(crlIssuer);
|
||||
|
||||
/*
|
||||
* Facilitate certification path construction with authority
|
||||
* key identifier and subject key identifier.
|
||||
*
|
||||
* In practice, conforming CAs MUST use the key identifier method,
|
||||
* and MUST include authority key identifier extension in all CRLs
|
||||
* issued. [section 5.2.1, RFC 2459]
|
||||
*/
|
||||
AuthorityKeyIdentifierExtension crlAKID = crl.getAuthKeyIdExtension();
|
||||
issuerSelector.setSkiAndSerialNumber(crlAKID);
|
||||
|
||||
matched = issuerSelector.match(cert);
|
||||
|
||||
// if AKID is unreliable, verify the CRL signature with the cert
|
||||
if (matched && (crlAKID == null ||
|
||||
cert.getAuthorityKeyIdentifierExtension() == null)) {
|
||||
try {
|
||||
crl.verify(cert.getPublicKey(), provider);
|
||||
matched = true;
|
||||
} catch (GeneralSecurityException e) {
|
||||
matched = false;
|
||||
}
|
||||
}
|
||||
|
||||
return matched;
|
||||
}
|
||||
}
|
||||
896
jdkSrc/jdk8/sun/security/provider/certpath/ForwardBuilder.java
Normal file
896
jdkSrc/jdk8/sun/security/provider/certpath/ForwardBuilder.java
Normal file
@@ -0,0 +1,896 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertPathValidatorException;
|
||||
import java.security.cert.PKIXReason;
|
||||
import java.security.cert.CertStore;
|
||||
import java.security.cert.CertStoreException;
|
||||
import java.security.cert.PKIXBuilderParameters;
|
||||
import java.security.cert.PKIXCertPathChecker;
|
||||
import java.security.cert.TrustAnchor;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.cert.X509CertSelector;
|
||||
import java.util.*;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
import sun.security.provider.certpath.PKIX.BuilderParams;
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.x509.AccessDescription;
|
||||
import sun.security.x509.AuthorityInfoAccessExtension;
|
||||
import sun.security.x509.AuthorityKeyIdentifierExtension;
|
||||
import static sun.security.x509.PKIXExtensions.*;
|
||||
import sun.security.x509.X500Name;
|
||||
import sun.security.x509.X509CertImpl;
|
||||
|
||||
/**
|
||||
* This class represents a forward builder, which is able to retrieve
|
||||
* matching certificates from CertStores and verify a particular certificate
|
||||
* against a ForwardState.
|
||||
*
|
||||
* @since 1.4
|
||||
* @author Yassir Elley
|
||||
* @author Sean Mullan
|
||||
*/
|
||||
class ForwardBuilder extends Builder {
|
||||
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
private final Set<X509Certificate> trustedCerts;
|
||||
private final Set<X500Principal> trustedSubjectDNs;
|
||||
private final Set<TrustAnchor> trustAnchors;
|
||||
private X509CertSelector eeSelector;
|
||||
private AdaptableX509CertSelector caSelector;
|
||||
private X509CertSelector caTargetSelector;
|
||||
TrustAnchor trustAnchor;
|
||||
private boolean searchAllCertStores = true;
|
||||
|
||||
/**
|
||||
* Initialize the builder with the input parameters.
|
||||
*
|
||||
* @param params the parameter set used to build a certification path
|
||||
*/
|
||||
ForwardBuilder(BuilderParams buildParams, boolean searchAllCertStores) {
|
||||
super(buildParams);
|
||||
|
||||
// populate sets of trusted certificates and subject DNs
|
||||
trustAnchors = buildParams.trustAnchors();
|
||||
trustedCerts = new HashSet<X509Certificate>(trustAnchors.size());
|
||||
trustedSubjectDNs = new HashSet<X500Principal>(trustAnchors.size());
|
||||
for (TrustAnchor anchor : trustAnchors) {
|
||||
X509Certificate trustedCert = anchor.getTrustedCert();
|
||||
if (trustedCert != null) {
|
||||
trustedCerts.add(trustedCert);
|
||||
trustedSubjectDNs.add(trustedCert.getSubjectX500Principal());
|
||||
} else {
|
||||
trustedSubjectDNs.add(anchor.getCA());
|
||||
}
|
||||
}
|
||||
this.searchAllCertStores = searchAllCertStores;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all certs from the specified CertStores that satisfy the
|
||||
* requirements specified in the parameters and the current
|
||||
* PKIX state (name constraints, policy constraints, etc).
|
||||
*
|
||||
* @param currentState the current state.
|
||||
* Must be an instance of <code>ForwardState</code>
|
||||
* @param certStores list of CertStores
|
||||
*/
|
||||
@Override
|
||||
Collection<X509Certificate> getMatchingCerts(State currentState,
|
||||
List<CertStore> certStores)
|
||||
throws CertStoreException, CertificateException, IOException
|
||||
{
|
||||
if (debug != null) {
|
||||
debug.println("ForwardBuilder.getMatchingCerts()...");
|
||||
}
|
||||
|
||||
ForwardState currState = (ForwardState) currentState;
|
||||
|
||||
/*
|
||||
* We store certs in a Set because we don't want duplicates.
|
||||
* As each cert is added, it is sorted based on the PKIXCertComparator
|
||||
* algorithm.
|
||||
*/
|
||||
Comparator<X509Certificate> comparator =
|
||||
new PKIXCertComparator(trustedSubjectDNs, currState.cert);
|
||||
Set<X509Certificate> certs = new TreeSet<>(comparator);
|
||||
|
||||
/*
|
||||
* Only look for EE certs if search has just started.
|
||||
*/
|
||||
if (currState.isInitial()) {
|
||||
getMatchingEECerts(currState, certStores, certs);
|
||||
}
|
||||
getMatchingCACerts(currState, certStores, certs);
|
||||
|
||||
return certs;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieves all end-entity certificates which satisfy constraints
|
||||
* and requirements specified in the parameters and PKIX state.
|
||||
*/
|
||||
private void getMatchingEECerts(ForwardState currentState,
|
||||
List<CertStore> certStores,
|
||||
Collection<X509Certificate> eeCerts)
|
||||
throws IOException
|
||||
{
|
||||
if (debug != null) {
|
||||
debug.println("ForwardBuilder.getMatchingEECerts()...");
|
||||
}
|
||||
/*
|
||||
* Compose a certificate matching rule to filter out
|
||||
* certs which don't satisfy constraints
|
||||
*
|
||||
* First, retrieve clone of current target cert constraints,
|
||||
* and then add more selection criteria based on current validation
|
||||
* state. Since selector never changes, cache local copy & reuse.
|
||||
*/
|
||||
if (eeSelector == null) {
|
||||
eeSelector = (X509CertSelector) targetCertConstraints.clone();
|
||||
|
||||
/*
|
||||
* Match on certificate validity date
|
||||
*/
|
||||
eeSelector.setCertificateValid(buildParams.date());
|
||||
|
||||
/*
|
||||
* Policy processing optimizations
|
||||
*/
|
||||
if (buildParams.explicitPolicyRequired()) {
|
||||
eeSelector.setPolicy(getMatchingPolicies());
|
||||
}
|
||||
/*
|
||||
* Require EE certs
|
||||
*/
|
||||
eeSelector.setBasicConstraints(-2);
|
||||
}
|
||||
|
||||
/* Retrieve matching EE certs from CertStores */
|
||||
addMatchingCerts(eeSelector, certStores, eeCerts, searchAllCertStores);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all CA certificates which satisfy constraints
|
||||
* and requirements specified in the parameters and PKIX state.
|
||||
*/
|
||||
private void getMatchingCACerts(ForwardState currentState,
|
||||
List<CertStore> certStores,
|
||||
Collection<X509Certificate> caCerts)
|
||||
throws IOException
|
||||
{
|
||||
if (debug != null) {
|
||||
debug.println("ForwardBuilder.getMatchingCACerts()...");
|
||||
}
|
||||
int initialSize = caCerts.size();
|
||||
|
||||
/*
|
||||
* Compose a CertSelector to filter out
|
||||
* certs which do not satisfy requirements.
|
||||
*/
|
||||
X509CertSelector sel = null;
|
||||
|
||||
if (currentState.isInitial()) {
|
||||
if (targetCertConstraints.getBasicConstraints() == -2) {
|
||||
// no need to continue: this means we never can match a CA cert
|
||||
return;
|
||||
}
|
||||
|
||||
/* This means a CA is the target, so match on same stuff as
|
||||
* getMatchingEECerts
|
||||
*/
|
||||
if (debug != null) {
|
||||
debug.println("ForwardBuilder.getMatchingCACerts(): " +
|
||||
"the target is a CA");
|
||||
}
|
||||
|
||||
if (caTargetSelector == null) {
|
||||
caTargetSelector =
|
||||
(X509CertSelector) targetCertConstraints.clone();
|
||||
|
||||
/*
|
||||
* Since we don't check the validity period of trusted
|
||||
* certificates, please don't set the certificate valid
|
||||
* criterion unless the trusted certificate matching is
|
||||
* completed.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Policy processing optimizations
|
||||
*/
|
||||
if (buildParams.explicitPolicyRequired())
|
||||
caTargetSelector.setPolicy(getMatchingPolicies());
|
||||
}
|
||||
|
||||
sel = caTargetSelector;
|
||||
} else {
|
||||
|
||||
if (caSelector == null) {
|
||||
caSelector = new AdaptableX509CertSelector();
|
||||
|
||||
/*
|
||||
* Since we don't check the validity period of trusted
|
||||
* certificates, please don't set the certificate valid
|
||||
* criterion unless the trusted certificate matching is
|
||||
* completed.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Policy processing optimizations
|
||||
*/
|
||||
if (buildParams.explicitPolicyRequired())
|
||||
caSelector.setPolicy(getMatchingPolicies());
|
||||
}
|
||||
|
||||
/*
|
||||
* Match on subject (issuer of previous cert)
|
||||
*/
|
||||
caSelector.setSubject(currentState.issuerDN);
|
||||
|
||||
/*
|
||||
* check the validity period
|
||||
*/
|
||||
caSelector.setValidityPeriod(currentState.cert.getNotBefore(),
|
||||
currentState.cert.getNotAfter());
|
||||
|
||||
sel = caSelector;
|
||||
}
|
||||
|
||||
/*
|
||||
* For compatibility, conservatively, we don't check the path
|
||||
* length constraint of trusted anchors. Please don't set the
|
||||
* basic constraints criterion unless the trusted certificate
|
||||
* matching is completed.
|
||||
*/
|
||||
sel.setBasicConstraints(-1);
|
||||
|
||||
for (X509Certificate trustedCert : trustedCerts) {
|
||||
if (sel.match(trustedCert)) {
|
||||
if (debug != null) {
|
||||
debug.println("ForwardBuilder.getMatchingCACerts: " +
|
||||
"found matching trust anchor." +
|
||||
"\n SN: " +
|
||||
Debug.toHexString(trustedCert.getSerialNumber()) +
|
||||
"\n Subject: " +
|
||||
trustedCert.getSubjectX500Principal() +
|
||||
"\n Issuer: " +
|
||||
trustedCert.getIssuerX500Principal());
|
||||
}
|
||||
caCerts.add(trustedCert);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The trusted certificate matching is completed. We need to match
|
||||
* on certificate validity date.
|
||||
*/
|
||||
sel.setCertificateValid(buildParams.date());
|
||||
|
||||
/*
|
||||
* Require CA certs with a pathLenConstraint that allows
|
||||
* at least as many CA certs that have already been traversed
|
||||
*/
|
||||
sel.setBasicConstraints(currentState.traversedCACerts);
|
||||
|
||||
/*
|
||||
* If we have already traversed as many CA certs as the maxPathLength
|
||||
* will allow us to, then we don't bother looking through these
|
||||
* certificate pairs. If maxPathLength has a value of -1, this
|
||||
* means it is unconstrained, so we always look through the
|
||||
* certificate pairs.
|
||||
*/
|
||||
if (currentState.isInitial() ||
|
||||
(buildParams.maxPathLength() == -1) ||
|
||||
(buildParams.maxPathLength() > currentState.traversedCACerts))
|
||||
{
|
||||
if (addMatchingCerts(sel, certStores,
|
||||
caCerts, searchAllCertStores)
|
||||
&& !searchAllCertStores) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!currentState.isInitial() && Builder.USE_AIA) {
|
||||
// check for AuthorityInformationAccess extension
|
||||
AuthorityInfoAccessExtension aiaExt =
|
||||
currentState.cert.getAuthorityInfoAccessExtension();
|
||||
if (aiaExt != null) {
|
||||
getCerts(aiaExt, caCerts);
|
||||
}
|
||||
}
|
||||
|
||||
if (debug != null) {
|
||||
int numCerts = caCerts.size() - initialSize;
|
||||
debug.println("ForwardBuilder.getMatchingCACerts: found " +
|
||||
numCerts + " CA certs");
|
||||
}
|
||||
}
|
||||
|
||||
// Thread-local gate to prevent recursive provider lookups
|
||||
private static ThreadLocal<Object> gate = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* Download certificates from the given AIA and add them to the
|
||||
* specified Collection.
|
||||
*/
|
||||
// cs.getCertificates(caSelector) returns a collection of X509Certificate's
|
||||
// because of the selector, so the cast is safe
|
||||
@SuppressWarnings("unchecked")
|
||||
private boolean getCerts(AuthorityInfoAccessExtension aiaExt,
|
||||
Collection<X509Certificate> certs)
|
||||
{
|
||||
if (Builder.USE_AIA == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<AccessDescription> adList = aiaExt.getAccessDescriptions();
|
||||
if (adList == null || adList.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gate.get() != null) {
|
||||
// Avoid recursive fetching of certificates
|
||||
if (debug != null) {
|
||||
debug.println("Recursive fetching of certs via the AIA " +
|
||||
"extension detected");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
gate.set(gate);
|
||||
try {
|
||||
boolean add = false;
|
||||
for (AccessDescription ad : adList) {
|
||||
CertStore cs = URICertStore.getInstance(ad);
|
||||
if (cs != null) {
|
||||
try {
|
||||
if (certs.addAll((Collection<X509Certificate>)
|
||||
cs.getCertificates(caSelector))) {
|
||||
add = true;
|
||||
if (!searchAllCertStores) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (CertStoreException cse) {
|
||||
if (debug != null) {
|
||||
debug.println("exception getting certs from CertStore:");
|
||||
cse.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return add;
|
||||
} finally {
|
||||
gate.set(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This inner class compares 2 PKIX certificates according to which
|
||||
* should be tried first when building a path from the target.
|
||||
* The preference order is as follows:
|
||||
*
|
||||
* Given trusted certificate(s):
|
||||
* Subject:ou=D,ou=C,o=B,c=A
|
||||
*
|
||||
* Preference order for current cert:
|
||||
*
|
||||
* 1) The key identifier of an AKID extension (if present) in the
|
||||
* previous certificate matches the key identifier in the SKID extension
|
||||
*
|
||||
* 2) Issuer matches a trusted subject
|
||||
* Issuer: ou=D,ou=C,o=B,c=A
|
||||
*
|
||||
* 3) Issuer is a descendant of a trusted subject (in order of
|
||||
* number of links to the trusted subject)
|
||||
* a) Issuer: ou=E,ou=D,ou=C,o=B,c=A [links=1]
|
||||
* b) Issuer: ou=F,ou=E,ou=D,ou=C,ou=B,c=A [links=2]
|
||||
*
|
||||
* 4) Issuer is an ancestor of a trusted subject (in order of number of
|
||||
* links to the trusted subject)
|
||||
* a) Issuer: ou=C,o=B,c=A [links=1]
|
||||
* b) Issuer: o=B,c=A [links=2]
|
||||
*
|
||||
* 5) Issuer is in the same namespace as a trusted subject (in order of
|
||||
* number of links to the trusted subject)
|
||||
* a) Issuer: ou=G,ou=C,o=B,c=A [links=2]
|
||||
* b) Issuer: ou=H,o=B,c=A [links=3]
|
||||
*
|
||||
* 6) Issuer is an ancestor of certificate subject (in order of number
|
||||
* of links to the certificate subject)
|
||||
* a) Issuer: ou=K,o=J,c=A
|
||||
* Subject: ou=L,ou=K,o=J,c=A
|
||||
* b) Issuer: o=J,c=A
|
||||
* Subject: ou=L,ou=K,0=J,c=A
|
||||
*
|
||||
* 7) Any other certificates
|
||||
*/
|
||||
static class PKIXCertComparator implements Comparator<X509Certificate> {
|
||||
|
||||
static final String METHOD_NME = "PKIXCertComparator.compare()";
|
||||
|
||||
private final Set<X500Principal> trustedSubjectDNs;
|
||||
private final X509CertSelector certSkidSelector;
|
||||
|
||||
PKIXCertComparator(Set<X500Principal> trustedSubjectDNs,
|
||||
X509CertImpl previousCert) throws IOException {
|
||||
this.trustedSubjectDNs = trustedSubjectDNs;
|
||||
this.certSkidSelector = getSelector(previousCert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an X509CertSelector for matching on the authority key
|
||||
* identifier, or null if not applicable.
|
||||
*/
|
||||
private X509CertSelector getSelector(X509CertImpl previousCert)
|
||||
throws IOException {
|
||||
if (previousCert != null) {
|
||||
AuthorityKeyIdentifierExtension akidExt =
|
||||
previousCert.getAuthorityKeyIdentifierExtension();
|
||||
if (akidExt != null) {
|
||||
byte[] skid = akidExt.getEncodedKeyIdentifier();
|
||||
if (skid != null) {
|
||||
X509CertSelector selector = new X509CertSelector();
|
||||
selector.setSubjectKeyIdentifier(skid);
|
||||
return selector;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param oCert1 First X509Certificate to be compared
|
||||
* @param oCert2 Second X509Certificate to be compared
|
||||
* @return -1 if oCert1 is preferable to oCert2, or
|
||||
* if oCert1 and oCert2 are equally preferable (in this
|
||||
* case it doesn't matter which is preferable, but we don't
|
||||
* return 0 because the comparator would behave strangely
|
||||
* when used in a SortedSet).
|
||||
* 1 if oCert2 is preferable to oCert1
|
||||
* 0 if oCert1.equals(oCert2). We only return 0 if the
|
||||
* certs are equal so that this comparator behaves
|
||||
* correctly when used in a SortedSet.
|
||||
* @throws ClassCastException if either argument is not of type
|
||||
* X509Certificate
|
||||
*/
|
||||
@Override
|
||||
public int compare(X509Certificate oCert1, X509Certificate oCert2) {
|
||||
|
||||
// if certs are the same, return 0
|
||||
if (oCert1.equals(oCert2)) return 0;
|
||||
|
||||
// If akid/skid match then it is preferable
|
||||
if (certSkidSelector != null) {
|
||||
if (certSkidSelector.match(oCert1)) {
|
||||
return -1;
|
||||
}
|
||||
if (certSkidSelector.match(oCert2)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
X500Principal cIssuer1 = oCert1.getIssuerX500Principal();
|
||||
X500Principal cIssuer2 = oCert2.getIssuerX500Principal();
|
||||
X500Name cIssuer1Name = X500Name.asX500Name(cIssuer1);
|
||||
X500Name cIssuer2Name = X500Name.asX500Name(cIssuer2);
|
||||
|
||||
if (debug != null) {
|
||||
debug.println(METHOD_NME + " o1 Issuer: " + cIssuer1);
|
||||
debug.println(METHOD_NME + " o2 Issuer: " + cIssuer2);
|
||||
}
|
||||
|
||||
/* If one cert's issuer matches a trusted subject, then it is
|
||||
* preferable.
|
||||
*/
|
||||
if (debug != null) {
|
||||
debug.println(METHOD_NME + " MATCH TRUSTED SUBJECT TEST...");
|
||||
}
|
||||
|
||||
boolean m1 = trustedSubjectDNs.contains(cIssuer1);
|
||||
boolean m2 = trustedSubjectDNs.contains(cIssuer2);
|
||||
if (debug != null) {
|
||||
debug.println(METHOD_NME + " m1: " + m1);
|
||||
debug.println(METHOD_NME + " m2: " + m2);
|
||||
}
|
||||
if (m1 && m2) {
|
||||
return -1;
|
||||
} else if (m1) {
|
||||
return -1;
|
||||
} else if (m2) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* If one cert's issuer is a naming descendant of a trusted subject,
|
||||
* then it is preferable, in order of increasing naming distance.
|
||||
*/
|
||||
if (debug != null) {
|
||||
debug.println(METHOD_NME + " NAMING DESCENDANT TEST...");
|
||||
}
|
||||
for (X500Principal tSubject : trustedSubjectDNs) {
|
||||
X500Name tSubjectName = X500Name.asX500Name(tSubject);
|
||||
int distanceTto1 =
|
||||
Builder.distance(tSubjectName, cIssuer1Name, -1);
|
||||
int distanceTto2 =
|
||||
Builder.distance(tSubjectName, cIssuer2Name, -1);
|
||||
if (debug != null) {
|
||||
debug.println(METHOD_NME +" distanceTto1: " + distanceTto1);
|
||||
debug.println(METHOD_NME +" distanceTto2: " + distanceTto2);
|
||||
}
|
||||
if (distanceTto1 > 0 || distanceTto2 > 0) {
|
||||
if (distanceTto1 == distanceTto2) {
|
||||
return -1;
|
||||
} else if (distanceTto1 > 0 && distanceTto2 <= 0) {
|
||||
return -1;
|
||||
} else if (distanceTto1 <= 0 && distanceTto2 > 0) {
|
||||
return 1;
|
||||
} else if (distanceTto1 < distanceTto2) {
|
||||
return -1;
|
||||
} else { // distanceTto1 > distanceTto2
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If one cert's issuer is a naming ancestor of a trusted subject,
|
||||
* then it is preferable, in order of increasing naming distance.
|
||||
*/
|
||||
if (debug != null) {
|
||||
debug.println(METHOD_NME + " NAMING ANCESTOR TEST...");
|
||||
}
|
||||
for (X500Principal tSubject : trustedSubjectDNs) {
|
||||
X500Name tSubjectName = X500Name.asX500Name(tSubject);
|
||||
|
||||
int distanceTto1 = Builder.distance
|
||||
(tSubjectName, cIssuer1Name, Integer.MAX_VALUE);
|
||||
int distanceTto2 = Builder.distance
|
||||
(tSubjectName, cIssuer2Name, Integer.MAX_VALUE);
|
||||
if (debug != null) {
|
||||
debug.println(METHOD_NME +" distanceTto1: " + distanceTto1);
|
||||
debug.println(METHOD_NME +" distanceTto2: " + distanceTto2);
|
||||
}
|
||||
if (distanceTto1 < 0 || distanceTto2 < 0) {
|
||||
if (distanceTto1 == distanceTto2) {
|
||||
return -1;
|
||||
} else if (distanceTto1 < 0 && distanceTto2 >= 0) {
|
||||
return -1;
|
||||
} else if (distanceTto1 >= 0 && distanceTto2 < 0) {
|
||||
return 1;
|
||||
} else if (distanceTto1 > distanceTto2) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If one cert's issuer is in the same namespace as a trusted
|
||||
* subject, then it is preferable, in order of increasing naming
|
||||
* distance.
|
||||
*/
|
||||
if (debug != null) {
|
||||
debug.println(METHOD_NME +" SAME NAMESPACE AS TRUSTED TEST...");
|
||||
}
|
||||
for (X500Principal tSubject : trustedSubjectDNs) {
|
||||
X500Name tSubjectName = X500Name.asX500Name(tSubject);
|
||||
X500Name tAo1 = tSubjectName.commonAncestor(cIssuer1Name);
|
||||
X500Name tAo2 = tSubjectName.commonAncestor(cIssuer2Name);
|
||||
if (debug != null) {
|
||||
debug.println(METHOD_NME +" tAo1: " + String.valueOf(tAo1));
|
||||
debug.println(METHOD_NME +" tAo2: " + String.valueOf(tAo2));
|
||||
}
|
||||
if (tAo1 != null || tAo2 != null) {
|
||||
if (tAo1 != null && tAo2 != null) {
|
||||
int hopsTto1 = Builder.hops
|
||||
(tSubjectName, cIssuer1Name, Integer.MAX_VALUE);
|
||||
int hopsTto2 = Builder.hops
|
||||
(tSubjectName, cIssuer2Name, Integer.MAX_VALUE);
|
||||
if (debug != null) {
|
||||
debug.println(METHOD_NME +" hopsTto1: " + hopsTto1);
|
||||
debug.println(METHOD_NME +" hopsTto2: " + hopsTto2);
|
||||
}
|
||||
if (hopsTto1 == hopsTto2) {
|
||||
} else if (hopsTto1 > hopsTto2) {
|
||||
return 1;
|
||||
} else { // hopsTto1 < hopsTto2
|
||||
return -1;
|
||||
}
|
||||
} else if (tAo1 == null) {
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* If one cert's issuer is an ancestor of that cert's subject,
|
||||
* then it is preferable, in order of increasing naming distance.
|
||||
*/
|
||||
if (debug != null) {
|
||||
debug.println(METHOD_NME+" CERT ISSUER/SUBJECT COMPARISON TEST...");
|
||||
}
|
||||
X500Principal cSubject1 = oCert1.getSubjectX500Principal();
|
||||
X500Principal cSubject2 = oCert2.getSubjectX500Principal();
|
||||
X500Name cSubject1Name = X500Name.asX500Name(cSubject1);
|
||||
X500Name cSubject2Name = X500Name.asX500Name(cSubject2);
|
||||
|
||||
if (debug != null) {
|
||||
debug.println(METHOD_NME + " o1 Subject: " + cSubject1);
|
||||
debug.println(METHOD_NME + " o2 Subject: " + cSubject2);
|
||||
}
|
||||
int distanceStoI1 = Builder.distance
|
||||
(cSubject1Name, cIssuer1Name, Integer.MAX_VALUE);
|
||||
int distanceStoI2 = Builder.distance
|
||||
(cSubject2Name, cIssuer2Name, Integer.MAX_VALUE);
|
||||
if (debug != null) {
|
||||
debug.println(METHOD_NME + " distanceStoI1: " + distanceStoI1);
|
||||
debug.println(METHOD_NME + " distanceStoI2: " + distanceStoI2);
|
||||
}
|
||||
if (distanceStoI2 > distanceStoI1) {
|
||||
return -1;
|
||||
} else if (distanceStoI2 < distanceStoI1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Otherwise, certs are equally preferable.
|
||||
*/
|
||||
if (debug != null) {
|
||||
debug.println(METHOD_NME + " no tests matched; RETURN 0");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies a matching certificate.
|
||||
*
|
||||
* This method executes the validation steps in the PKIX path
|
||||
* validation algorithm <draft-ietf-pkix-new-part1-08.txt> which were
|
||||
* not satisfied by the selection criteria used by getCertificates()
|
||||
* to find the certs and only the steps that can be executed in a
|
||||
* forward direction (target to trust anchor). Those steps that can
|
||||
* only be executed in a reverse direction are deferred until the
|
||||
* complete path has been built.
|
||||
*
|
||||
* Trust anchor certs are not validated.
|
||||
*
|
||||
* If the last certificate is being verified (the one whose subject
|
||||
* matches the target subject, then steps in 6.1.4 of the PKIX
|
||||
* Certification Path Validation algorithm are NOT executed,
|
||||
* regardless of whether or not the last cert is an end-entity
|
||||
* cert or not. This allows callers to certify CA certs as
|
||||
* well as EE certs.
|
||||
*
|
||||
* @param cert the certificate to be verified
|
||||
* @param currentState the current state against which the cert is verified
|
||||
* @param certPathList the certPathList generated thus far
|
||||
*/
|
||||
@Override
|
||||
void verifyCert(X509Certificate cert, State currentState,
|
||||
List<X509Certificate> certPathList)
|
||||
throws GeneralSecurityException
|
||||
{
|
||||
if (debug != null) {
|
||||
debug.println("ForwardBuilder.verifyCert(SN: "
|
||||
+ Debug.toHexString(cert.getSerialNumber())
|
||||
+ "\n Issuer: " + cert.getIssuerX500Principal() + ")"
|
||||
+ "\n Subject: " + cert.getSubjectX500Principal() + ")");
|
||||
}
|
||||
|
||||
ForwardState currState = (ForwardState)currentState;
|
||||
|
||||
// Don't bother to verify untrusted certificate more.
|
||||
currState.untrustedChecker.check(cert, Collections.<String>emptySet());
|
||||
|
||||
/* check if trusted cert */
|
||||
boolean isTrustedCert = trustedCerts.contains(cert);
|
||||
|
||||
/* we don't perform any validation of the trusted cert */
|
||||
if (!isTrustedCert) {
|
||||
/*
|
||||
* Check CRITICAL private extensions for user checkers that
|
||||
* support forward checking (forwardCheckers) and remove
|
||||
* ones we know how to check.
|
||||
*/
|
||||
Set<String> unresCritExts = cert.getCriticalExtensionOIDs();
|
||||
if (unresCritExts == null) {
|
||||
unresCritExts = Collections.<String>emptySet();
|
||||
}
|
||||
for (PKIXCertPathChecker checker : currState.forwardCheckers) {
|
||||
checker.check(cert, unresCritExts);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove extensions from user checkers that don't support
|
||||
* forward checking. After this step, we will have removed
|
||||
* all extensions that all user checkers are capable of
|
||||
* processing.
|
||||
*/
|
||||
for (PKIXCertPathChecker checker : buildParams.certPathCheckers()) {
|
||||
if (!checker.isForwardCheckingSupported()) {
|
||||
Set<String> supportedExts = checker.getSupportedExtensions();
|
||||
if (supportedExts != null) {
|
||||
unresCritExts.removeAll(supportedExts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Look at the remaining extensions and remove any ones we know how
|
||||
* to check. If there are any left, throw an exception!
|
||||
*/
|
||||
if (!unresCritExts.isEmpty()) {
|
||||
unresCritExts.remove(BasicConstraints_Id.toString());
|
||||
unresCritExts.remove(NameConstraints_Id.toString());
|
||||
unresCritExts.remove(CertificatePolicies_Id.toString());
|
||||
unresCritExts.remove(PolicyMappings_Id.toString());
|
||||
unresCritExts.remove(PolicyConstraints_Id.toString());
|
||||
unresCritExts.remove(InhibitAnyPolicy_Id.toString());
|
||||
unresCritExts.remove(SubjectAlternativeName_Id.toString());
|
||||
unresCritExts.remove(KeyUsage_Id.toString());
|
||||
unresCritExts.remove(ExtendedKeyUsage_Id.toString());
|
||||
|
||||
if (!unresCritExts.isEmpty())
|
||||
throw new CertPathValidatorException
|
||||
("Unrecognized critical extension(s)", null, null, -1,
|
||||
PKIXReason.UNRECOGNIZED_CRIT_EXT);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* if this is the target certificate (init=true), then we are
|
||||
* not able to do any more verification, so just return
|
||||
*/
|
||||
if (currState.isInitial()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* we don't perform any validation of the trusted cert */
|
||||
if (!isTrustedCert) {
|
||||
/* Make sure this is a CA cert */
|
||||
if (cert.getBasicConstraints() == -1) {
|
||||
throw new CertificateException("cert is NOT a CA cert");
|
||||
}
|
||||
|
||||
/*
|
||||
* Check keyUsage extension
|
||||
*/
|
||||
KeyChecker.verifyCAKeyUsage(cert);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies whether the input certificate completes the path.
|
||||
* First checks the cert against each trust anchor that was specified,
|
||||
* in order, and returns true if the cert matches the trust anchor
|
||||
* specified as a certificate or has the same key and subject of an anchor
|
||||
* specified as a trusted {pubkey, caname} pair.
|
||||
* If no match has been found, does a second check of the cert against
|
||||
* anchors specified as a trusted {pubkey, caname} pair to see if the cert
|
||||
* was issued by that anchor.
|
||||
* Returns false if none of the trust anchors are valid for this cert.
|
||||
*
|
||||
* @param cert the certificate to test
|
||||
* @return a boolean value indicating whether the cert completes the path.
|
||||
*/
|
||||
@Override
|
||||
boolean isPathCompleted(X509Certificate cert) {
|
||||
List<TrustAnchor> otherAnchors = new ArrayList<>();
|
||||
// first, check if cert is already trusted
|
||||
for (TrustAnchor anchor : trustAnchors) {
|
||||
if (anchor.getTrustedCert() != null) {
|
||||
if (cert.equals(anchor.getTrustedCert())) {
|
||||
this.trustAnchor = anchor;
|
||||
return true;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
X500Principal principal = anchor.getCA();
|
||||
PublicKey publicKey = anchor.getCAPublicKey();
|
||||
|
||||
if (principal != null && publicKey != null &&
|
||||
principal.equals(cert.getSubjectX500Principal())) {
|
||||
if (publicKey.equals(cert.getPublicKey())) {
|
||||
// the cert itself is a trust anchor
|
||||
this.trustAnchor = anchor;
|
||||
return true;
|
||||
}
|
||||
// else, it is a self-issued certificate of the anchor
|
||||
}
|
||||
otherAnchors.add(anchor);
|
||||
}
|
||||
// next, check if cert is issued by anchor specified by key/name
|
||||
for (TrustAnchor anchor : otherAnchors) {
|
||||
X500Principal principal = anchor.getCA();
|
||||
PublicKey publicKey = anchor.getCAPublicKey();
|
||||
// Check subject/issuer name chaining
|
||||
if (principal == null ||
|
||||
!principal.equals(cert.getIssuerX500Principal())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip anchor if it contains a DSA key with no DSA params
|
||||
if (PKIX.isDSAPublicKeyWithoutParams(publicKey)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check signature
|
||||
*/
|
||||
try {
|
||||
cert.verify(publicKey, buildParams.sigProvider());
|
||||
} catch (InvalidKeyException ike) {
|
||||
if (debug != null) {
|
||||
debug.println("ForwardBuilder.isPathCompleted() invalid "
|
||||
+ "DSA key found");
|
||||
}
|
||||
continue;
|
||||
} catch (GeneralSecurityException e){
|
||||
if (debug != null) {
|
||||
debug.println("ForwardBuilder.isPathCompleted() " +
|
||||
"unexpected exception");
|
||||
e.printStackTrace();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
this.trustAnchor = anchor;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Adds the certificate to the certPathList
|
||||
*
|
||||
* @param cert the certificate to be added
|
||||
* @param certPathList the certification path list
|
||||
*/
|
||||
@Override
|
||||
void addCertToPath(X509Certificate cert,
|
||||
LinkedList<X509Certificate> certPathList)
|
||||
{
|
||||
certPathList.addFirst(cert);
|
||||
}
|
||||
|
||||
/** Removes final certificate from the certPathList
|
||||
*
|
||||
* @param certPathList the certification path list
|
||||
*/
|
||||
@Override
|
||||
void removeFinalCertFromPath(LinkedList<X509Certificate> certPathList) {
|
||||
certPathList.removeFirst();
|
||||
}
|
||||
}
|
||||
191
jdkSrc/jdk8/sun/security/provider/certpath/ForwardState.java
Normal file
191
jdkSrc/jdk8/sun/security/provider/certpath/ForwardState.java
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertPathValidatorException;
|
||||
import java.security.cert.PKIXCertPathChecker;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.x509.X509CertImpl;
|
||||
|
||||
/**
|
||||
* A specification of a forward PKIX validation state
|
||||
* which is initialized by each build and updated each time a
|
||||
* certificate is added to the current path.
|
||||
* @since 1.4
|
||||
* @author Yassir Elley
|
||||
*/
|
||||
class ForwardState implements State {
|
||||
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
|
||||
/* The issuer DN of the last cert in the path */
|
||||
X500Principal issuerDN;
|
||||
|
||||
/* The last cert in the path */
|
||||
X509CertImpl cert;
|
||||
|
||||
/*
|
||||
* The number of intermediate CA certs which have been traversed so
|
||||
* far in the path
|
||||
*/
|
||||
int traversedCACerts;
|
||||
|
||||
/* Flag indicating if state is initial (path is just starting) */
|
||||
private boolean init = true;
|
||||
|
||||
/* the untrusted certificates checker */
|
||||
UntrustedChecker untrustedChecker;
|
||||
|
||||
/* The list of user-defined checkers that support forward checking */
|
||||
ArrayList<PKIXCertPathChecker> forwardCheckers;
|
||||
|
||||
/* Flag indicating if last cert in path is self-issued */
|
||||
boolean selfIssued;
|
||||
|
||||
/**
|
||||
* Returns a boolean flag indicating if the state is initial
|
||||
* (just starting)
|
||||
*
|
||||
* @return boolean flag indicating if the state is initial (just starting)
|
||||
*/
|
||||
@Override
|
||||
public boolean isInitial() {
|
||||
return init;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display state for debugging purposes
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("State [");
|
||||
sb.append("\n issuerDN of last cert: ").append(issuerDN);
|
||||
sb.append("\n traversedCACerts: ").append(traversedCACerts);
|
||||
sb.append("\n init: ").append(String.valueOf(init));
|
||||
sb.append("\n selfIssued: ").append
|
||||
(String.valueOf(selfIssued));
|
||||
sb.append("]\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the state.
|
||||
*
|
||||
* @param certPathCheckers the list of user-defined PKIXCertPathCheckers
|
||||
*/
|
||||
public void initState(List<PKIXCertPathChecker> certPathCheckers)
|
||||
throws CertPathValidatorException
|
||||
{
|
||||
traversedCACerts = 0;
|
||||
|
||||
/*
|
||||
* Populate forwardCheckers with every user-defined checker
|
||||
* that supports forward checking and initialize the forwardCheckers
|
||||
*/
|
||||
forwardCheckers = new ArrayList<PKIXCertPathChecker>();
|
||||
for (PKIXCertPathChecker checker : certPathCheckers) {
|
||||
if (checker.isForwardCheckingSupported()) {
|
||||
checker.init(true);
|
||||
forwardCheckers.add(checker);
|
||||
}
|
||||
}
|
||||
|
||||
init = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the state with the next certificate added to the path.
|
||||
*
|
||||
* @param cert the certificate which is used to update the state
|
||||
*/
|
||||
@Override
|
||||
public void updateState(X509Certificate cert)
|
||||
throws CertificateException, IOException, CertPathValidatorException {
|
||||
|
||||
if (cert == null)
|
||||
return;
|
||||
|
||||
X509CertImpl icert = X509CertImpl.toImpl(cert);
|
||||
|
||||
/* update certificate */
|
||||
this.cert = icert;
|
||||
|
||||
/* update issuer DN */
|
||||
issuerDN = cert.getIssuerX500Principal();
|
||||
|
||||
selfIssued = X509CertImpl.isSelfIssued(cert);
|
||||
if (!selfIssued) {
|
||||
|
||||
/*
|
||||
* update traversedCACerts only if this is a non-self-issued
|
||||
* intermediate CA cert
|
||||
*/
|
||||
if (!init && cert.getBasicConstraints() != -1) {
|
||||
traversedCACerts++;
|
||||
}
|
||||
}
|
||||
|
||||
init = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clone current state. The state is cloned as each cert is
|
||||
* added to the path. This is necessary if backtracking occurs,
|
||||
* and a prior state needs to be restored.
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked") // Safe casts assuming clone() works correctly
|
||||
public Object clone() {
|
||||
try {
|
||||
ForwardState clonedState = (ForwardState) super.clone();
|
||||
|
||||
/* clone checkers, if cloneable */
|
||||
clonedState.forwardCheckers = (ArrayList<PKIXCertPathChecker>)
|
||||
forwardCheckers.clone();
|
||||
ListIterator<PKIXCertPathChecker> li =
|
||||
clonedState.forwardCheckers.listIterator();
|
||||
while (li.hasNext()) {
|
||||
PKIXCertPathChecker checker = li.next();
|
||||
if (checker instanceof Cloneable) {
|
||||
li.set((PKIXCertPathChecker)checker.clone());
|
||||
}
|
||||
}
|
||||
|
||||
return clonedState;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new InternalError(e.toString(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,424 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.cert.*;
|
||||
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
/**
|
||||
* A <code>CertStore</code> that retrieves <code>Certificates</code> and
|
||||
* <code>CRL</code>s from a <code>Collection</code>.
|
||||
* <p>
|
||||
* This implementation is functionally equivalent to CollectionCertStore
|
||||
* with two differences:
|
||||
* <ol>
|
||||
* <li>Upon construction, the elements in the specified Collection are
|
||||
* partially indexed. X509Certificates are indexed by subject, X509CRLs
|
||||
* by issuer, non-X509 Certificates and CRLs are copied without indexing,
|
||||
* other objects are ignored. This increases CertStore construction time
|
||||
* but allows significant speedups for searches which specify the indexed
|
||||
* attributes, in particular for large Collections (reduction from linear
|
||||
* time to effectively constant time). Searches for non-indexed queries
|
||||
* are as fast (or marginally faster) than for the standard
|
||||
* CollectionCertStore. Certificate subjects and CRL issuers
|
||||
* were found to be specified in most searches used internally by the
|
||||
* CertPath provider. Additional attributes could indexed if there are
|
||||
* queries that justify the effort.
|
||||
*
|
||||
* <li>Changes to the specified Collection after construction time are
|
||||
* not detected and ignored. This is because there is no way to efficiently
|
||||
* detect if a Collection has been modified, a full traversal would be
|
||||
* required. That would degrade lookup performance to linear time and
|
||||
* eliminated the benefit of indexing. We may fix this via the introduction
|
||||
* of new public APIs in the future.
|
||||
* </ol>
|
||||
* <p>
|
||||
* Before calling the {@link #engineGetCertificates engineGetCertificates} or
|
||||
* {@link #engineGetCRLs engineGetCRLs} methods, the
|
||||
* {@link #CollectionCertStore(CertStoreParameters)
|
||||
* CollectionCertStore(CertStoreParameters)} constructor is called to
|
||||
* create the <code>CertStore</code> and establish the
|
||||
* <code>Collection</code> from which <code>Certificate</code>s and
|
||||
* <code>CRL</code>s will be retrieved. If the specified
|
||||
* <code>Collection</code> contains an object that is not a
|
||||
* <code>Certificate</code> or <code>CRL</code>, that object will be
|
||||
* ignored.
|
||||
* <p>
|
||||
* <b>Concurrent Access</b>
|
||||
* <p>
|
||||
* As described in the javadoc for <code>CertStoreSpi</code>, the
|
||||
* <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods
|
||||
* must be thread-safe. That is, multiple threads may concurrently
|
||||
* invoke these methods on a single <code>CollectionCertStore</code>
|
||||
* object (or more than one) with no ill effects.
|
||||
* <p>
|
||||
* This is achieved by requiring that the <code>Collection</code> passed to
|
||||
* the {@link #CollectionCertStore(CertStoreParameters)
|
||||
* CollectionCertStore(CertStoreParameters)} constructor (via the
|
||||
* <code>CollectionCertStoreParameters</code> object) must have fail-fast
|
||||
* iterators. Simultaneous modifications to the <code>Collection</code> can thus be
|
||||
* detected and certificate or CRL retrieval can be retried. The fact that
|
||||
* <code>Certificate</code>s and <code>CRL</code>s must be thread-safe is also
|
||||
* essential.
|
||||
*
|
||||
* @see java.security.cert.CertStore
|
||||
* @see CollectionCertStore
|
||||
*
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public class IndexedCollectionCertStore extends CertStoreSpi {
|
||||
|
||||
/**
|
||||
* Map X500Principal(subject) -> X509Certificate | List of X509Certificate
|
||||
*/
|
||||
private Map<X500Principal, Object> certSubjects;
|
||||
/**
|
||||
* Map X500Principal(issuer) -> X509CRL | List of X509CRL
|
||||
*/
|
||||
private Map<X500Principal, Object> crlIssuers;
|
||||
/**
|
||||
* Sets of non-X509 certificates and CRLs
|
||||
*/
|
||||
private Set<Certificate> otherCertificates;
|
||||
private Set<CRL> otherCRLs;
|
||||
|
||||
/**
|
||||
* Creates a <code>CertStore</code> with the specified parameters.
|
||||
* For this class, the parameters object must be an instance of
|
||||
* <code>CollectionCertStoreParameters</code>.
|
||||
*
|
||||
* @param params the algorithm parameters
|
||||
* @exception InvalidAlgorithmParameterException if params is not an
|
||||
* instance of <code>CollectionCertStoreParameters</code>
|
||||
*/
|
||||
public IndexedCollectionCertStore(CertStoreParameters params)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
super(params);
|
||||
if (!(params instanceof CollectionCertStoreParameters)) {
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"parameters must be CollectionCertStoreParameters");
|
||||
}
|
||||
Collection<?> coll = ((CollectionCertStoreParameters)params).getCollection();
|
||||
if (coll == null) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Collection must not be null");
|
||||
}
|
||||
buildIndex(coll);
|
||||
}
|
||||
|
||||
/**
|
||||
* Index the specified Collection copying all references to Certificates
|
||||
* and CRLs.
|
||||
*/
|
||||
private void buildIndex(Collection<?> coll) {
|
||||
certSubjects = new HashMap<X500Principal, Object>();
|
||||
crlIssuers = new HashMap<X500Principal, Object>();
|
||||
otherCertificates = null;
|
||||
otherCRLs = null;
|
||||
for (Object obj : coll) {
|
||||
if (obj instanceof X509Certificate) {
|
||||
indexCertificate((X509Certificate)obj);
|
||||
} else if (obj instanceof X509CRL) {
|
||||
indexCRL((X509CRL)obj);
|
||||
} else if (obj instanceof Certificate) {
|
||||
if (otherCertificates == null) {
|
||||
otherCertificates = new HashSet<Certificate>();
|
||||
}
|
||||
otherCertificates.add((Certificate)obj);
|
||||
} else if (obj instanceof CRL) {
|
||||
if (otherCRLs == null) {
|
||||
otherCRLs = new HashSet<CRL>();
|
||||
}
|
||||
otherCRLs.add((CRL)obj);
|
||||
} else {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
if (otherCertificates == null) {
|
||||
otherCertificates = Collections.<Certificate>emptySet();
|
||||
}
|
||||
if (otherCRLs == null) {
|
||||
otherCRLs = Collections.<CRL>emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an X509Certificate to the index.
|
||||
*/
|
||||
private void indexCertificate(X509Certificate cert) {
|
||||
X500Principal subject = cert.getSubjectX500Principal();
|
||||
Object oldEntry = certSubjects.put(subject, cert);
|
||||
if (oldEntry != null) { // assume this is unlikely
|
||||
if (oldEntry instanceof X509Certificate) {
|
||||
if (cert.equals(oldEntry)) {
|
||||
return;
|
||||
}
|
||||
List<X509Certificate> list = new ArrayList<>(2);
|
||||
list.add(cert);
|
||||
list.add((X509Certificate)oldEntry);
|
||||
certSubjects.put(subject, list);
|
||||
} else {
|
||||
@SuppressWarnings("unchecked") // See certSubjects javadoc.
|
||||
List<X509Certificate> list = (List<X509Certificate>)oldEntry;
|
||||
if (list.contains(cert) == false) {
|
||||
list.add(cert);
|
||||
}
|
||||
certSubjects.put(subject, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an X509CRL to the index.
|
||||
*/
|
||||
private void indexCRL(X509CRL crl) {
|
||||
X500Principal issuer = crl.getIssuerX500Principal();
|
||||
Object oldEntry = crlIssuers.put(issuer, crl);
|
||||
if (oldEntry != null) { // assume this is unlikely
|
||||
if (oldEntry instanceof X509CRL) {
|
||||
if (crl.equals(oldEntry)) {
|
||||
return;
|
||||
}
|
||||
List<X509CRL> list = new ArrayList<>(2);
|
||||
list.add(crl);
|
||||
list.add((X509CRL)oldEntry);
|
||||
crlIssuers.put(issuer, list);
|
||||
} else {
|
||||
// See crlIssuers javadoc.
|
||||
@SuppressWarnings("unchecked")
|
||||
List<X509CRL> list = (List<X509CRL>)oldEntry;
|
||||
if (list.contains(crl) == false) {
|
||||
list.add(crl);
|
||||
}
|
||||
crlIssuers.put(issuer, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>Collection</code> of <code>Certificate</code>s that
|
||||
* match the specified selector. If no <code>Certificate</code>s
|
||||
* match the selector, an empty <code>Collection</code> will be returned.
|
||||
*
|
||||
* @param selector a <code>CertSelector</code> used to select which
|
||||
* <code>Certificate</code>s should be returned. Specify <code>null</code>
|
||||
* to return all <code>Certificate</code>s.
|
||||
* @return a <code>Collection</code> of <code>Certificate</code>s that
|
||||
* match the specified selector
|
||||
* @throws CertStoreException if an exception occurs
|
||||
*/
|
||||
@Override
|
||||
public Collection<? extends Certificate> engineGetCertificates(CertSelector selector)
|
||||
throws CertStoreException {
|
||||
|
||||
// no selector means match all
|
||||
if (selector == null) {
|
||||
Set<Certificate> matches = new HashSet<>();
|
||||
matchX509Certs(new X509CertSelector(), matches);
|
||||
matches.addAll(otherCertificates);
|
||||
return matches;
|
||||
}
|
||||
|
||||
if (selector instanceof X509CertSelector == false) {
|
||||
Set<Certificate> matches = new HashSet<>();
|
||||
matchX509Certs(selector, matches);
|
||||
for (Certificate cert : otherCertificates) {
|
||||
if (selector.match(cert)) {
|
||||
matches.add(cert);
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
if (certSubjects.isEmpty()) {
|
||||
return Collections.<X509Certificate>emptySet();
|
||||
}
|
||||
X509CertSelector x509Selector = (X509CertSelector)selector;
|
||||
// see if the subject is specified
|
||||
X500Principal subject;
|
||||
X509Certificate matchCert = x509Selector.getCertificate();
|
||||
if (matchCert != null) {
|
||||
subject = matchCert.getSubjectX500Principal();
|
||||
} else {
|
||||
subject = x509Selector.getSubject();
|
||||
}
|
||||
if (subject != null) {
|
||||
// yes, narrow down candidates to indexed possibilities
|
||||
Object entry = certSubjects.get(subject);
|
||||
if (entry == null) {
|
||||
return Collections.<X509Certificate>emptySet();
|
||||
}
|
||||
if (entry instanceof X509Certificate) {
|
||||
X509Certificate x509Entry = (X509Certificate)entry;
|
||||
if (x509Selector.match(x509Entry)) {
|
||||
return Collections.singleton(x509Entry);
|
||||
} else {
|
||||
return Collections.<X509Certificate>emptySet();
|
||||
}
|
||||
} else {
|
||||
// See certSubjects javadoc.
|
||||
@SuppressWarnings("unchecked")
|
||||
List<X509Certificate> list = (List<X509Certificate>)entry;
|
||||
Set<X509Certificate> matches = new HashSet<>(16);
|
||||
for (X509Certificate cert : list) {
|
||||
if (x509Selector.match(cert)) {
|
||||
matches.add(cert);
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
}
|
||||
// cannot use index, iterate all
|
||||
Set<Certificate> matches = new HashSet<>(16);
|
||||
matchX509Certs(x509Selector, matches);
|
||||
return matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate through all the X509Certificates and add matches to the
|
||||
* collection.
|
||||
*/
|
||||
private void matchX509Certs(CertSelector selector,
|
||||
Collection<Certificate> matches) {
|
||||
|
||||
for (Object obj : certSubjects.values()) {
|
||||
if (obj instanceof X509Certificate) {
|
||||
X509Certificate cert = (X509Certificate)obj;
|
||||
if (selector.match(cert)) {
|
||||
matches.add(cert);
|
||||
}
|
||||
} else {
|
||||
// See certSubjects javadoc.
|
||||
@SuppressWarnings("unchecked")
|
||||
List<X509Certificate> list = (List<X509Certificate>)obj;
|
||||
for (X509Certificate cert : list) {
|
||||
if (selector.match(cert)) {
|
||||
matches.add(cert);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>Collection</code> of <code>CRL</code>s that
|
||||
* match the specified selector. If no <code>CRL</code>s
|
||||
* match the selector, an empty <code>Collection</code> will be returned.
|
||||
*
|
||||
* @param selector a <code>CRLSelector</code> used to select which
|
||||
* <code>CRL</code>s should be returned. Specify <code>null</code>
|
||||
* to return all <code>CRL</code>s.
|
||||
* @return a <code>Collection</code> of <code>CRL</code>s that
|
||||
* match the specified selector
|
||||
* @throws CertStoreException if an exception occurs
|
||||
*/
|
||||
@Override
|
||||
public Collection<CRL> engineGetCRLs(CRLSelector selector)
|
||||
throws CertStoreException {
|
||||
|
||||
if (selector == null) {
|
||||
Set<CRL> matches = new HashSet<>();
|
||||
matchX509CRLs(new X509CRLSelector(), matches);
|
||||
matches.addAll(otherCRLs);
|
||||
return matches;
|
||||
}
|
||||
|
||||
if (selector instanceof X509CRLSelector == false) {
|
||||
Set<CRL> matches = new HashSet<>();
|
||||
matchX509CRLs(selector, matches);
|
||||
for (CRL crl : otherCRLs) {
|
||||
if (selector.match(crl)) {
|
||||
matches.add(crl);
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
if (crlIssuers.isEmpty()) {
|
||||
return Collections.<CRL>emptySet();
|
||||
}
|
||||
X509CRLSelector x509Selector = (X509CRLSelector)selector;
|
||||
// see if the issuer is specified
|
||||
Collection<X500Principal> issuers = x509Selector.getIssuers();
|
||||
if (issuers != null) {
|
||||
HashSet<CRL> matches = new HashSet<>(16);
|
||||
for (X500Principal issuer : issuers) {
|
||||
Object entry = crlIssuers.get(issuer);
|
||||
if (entry == null) {
|
||||
// empty
|
||||
} else if (entry instanceof X509CRL) {
|
||||
X509CRL crl = (X509CRL)entry;
|
||||
if (x509Selector.match(crl)) {
|
||||
matches.add(crl);
|
||||
}
|
||||
} else { // List
|
||||
// See crlIssuers javadoc.
|
||||
@SuppressWarnings("unchecked")
|
||||
List<X509CRL> list = (List<X509CRL>)entry;
|
||||
for (X509CRL crl : list) {
|
||||
if (x509Selector.match(crl)) {
|
||||
matches.add(crl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
// cannot use index, iterate all
|
||||
Set<CRL> matches = new HashSet<>(16);
|
||||
matchX509CRLs(x509Selector, matches);
|
||||
return matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate through all the X509CRLs and add matches to the
|
||||
* collection.
|
||||
*/
|
||||
private void matchX509CRLs(CRLSelector selector, Collection<CRL> matches) {
|
||||
for (Object obj : crlIssuers.values()) {
|
||||
if (obj instanceof X509CRL) {
|
||||
X509CRL crl = (X509CRL)obj;
|
||||
if (selector.match(crl)) {
|
||||
matches.add(crl);
|
||||
}
|
||||
} else {
|
||||
// See crlIssuers javadoc.
|
||||
@SuppressWarnings("unchecked")
|
||||
List<X509CRL> list = (List<X509CRL>)obj;
|
||||
for (X509CRL crl : list) {
|
||||
if (selector.match(crl)) {
|
||||
matches.add(crl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
169
jdkSrc/jdk8/sun/security/provider/certpath/KeyChecker.java
Normal file
169
jdkSrc/jdk8/sun/security/provider/certpath/KeyChecker.java
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.util.*;
|
||||
import java.security.cert.*;
|
||||
import java.security.cert.PKIXReason;
|
||||
|
||||
import sun.security.util.Debug;
|
||||
import static sun.security.x509.PKIXExtensions.*;
|
||||
|
||||
/**
|
||||
* KeyChecker is a <code>PKIXCertPathChecker</code> that checks that the
|
||||
* keyCertSign bit is set in the keyUsage extension in an intermediate CA
|
||||
* certificate. It also checks whether the final certificate in a
|
||||
* certification path meets the specified target constraints specified as
|
||||
* a CertSelector in the PKIXParameters passed to the CertPathValidator.
|
||||
*
|
||||
* @since 1.4
|
||||
* @author Yassir Elley
|
||||
*/
|
||||
class KeyChecker extends PKIXCertPathChecker {
|
||||
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
private final int certPathLen;
|
||||
private final CertSelector targetConstraints;
|
||||
private int remainingCerts;
|
||||
|
||||
private Set<String> supportedExts;
|
||||
|
||||
/**
|
||||
* Creates a KeyChecker.
|
||||
*
|
||||
* @param certPathLen allowable cert path length
|
||||
* @param targetCertSel a CertSelector object specifying the constraints
|
||||
* on the target certificate
|
||||
*/
|
||||
KeyChecker(int certPathLen, CertSelector targetCertSel) {
|
||||
this.certPathLen = certPathLen;
|
||||
this.targetConstraints = targetCertSel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the internal state of the checker from parameters
|
||||
* specified in the constructor
|
||||
*/
|
||||
@Override
|
||||
public void init(boolean forward) throws CertPathValidatorException {
|
||||
if (!forward) {
|
||||
remainingCerts = certPathLen;
|
||||
} else {
|
||||
throw new CertPathValidatorException
|
||||
("forward checking not supported");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForwardCheckingSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedExtensions() {
|
||||
if (supportedExts == null) {
|
||||
supportedExts = new HashSet<String>(3);
|
||||
supportedExts.add(KeyUsage_Id.toString());
|
||||
supportedExts.add(ExtendedKeyUsage_Id.toString());
|
||||
supportedExts.add(SubjectAlternativeName_Id.toString());
|
||||
supportedExts = Collections.unmodifiableSet(supportedExts);
|
||||
}
|
||||
return supportedExts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that keyUsage and target constraints are satisfied by
|
||||
* the specified certificate.
|
||||
*
|
||||
* @param cert the Certificate
|
||||
* @param unresolvedCritExts the unresolved critical extensions
|
||||
* @throws CertPathValidatorException if certificate does not verify
|
||||
*/
|
||||
@Override
|
||||
public void check(Certificate cert, Collection<String> unresCritExts)
|
||||
throws CertPathValidatorException
|
||||
{
|
||||
X509Certificate currCert = (X509Certificate)cert;
|
||||
|
||||
remainingCerts--;
|
||||
|
||||
// if final certificate, check that target constraints are satisfied
|
||||
if (remainingCerts == 0) {
|
||||
if (targetConstraints != null &&
|
||||
targetConstraints.match(currCert) == false) {
|
||||
throw new CertPathValidatorException("target certificate " +
|
||||
"constraints check failed");
|
||||
}
|
||||
} else {
|
||||
// otherwise, verify that keyCertSign bit is set in CA certificate
|
||||
verifyCAKeyUsage(currCert);
|
||||
}
|
||||
|
||||
// remove the extensions that we have checked
|
||||
if (unresCritExts != null && !unresCritExts.isEmpty()) {
|
||||
unresCritExts.remove(KeyUsage_Id.toString());
|
||||
unresCritExts.remove(ExtendedKeyUsage_Id.toString());
|
||||
unresCritExts.remove(SubjectAlternativeName_Id.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// the index of keyCertSign in the boolean KeyUsage array
|
||||
private static final int KEY_CERT_SIGN = 5;
|
||||
/**
|
||||
* Verifies the key usage extension in a CA cert.
|
||||
* The key usage extension, if present, must assert the keyCertSign bit.
|
||||
* The extended key usage extension is not checked (see CR 4776794 for
|
||||
* more information).
|
||||
*/
|
||||
static void verifyCAKeyUsage(X509Certificate cert)
|
||||
throws CertPathValidatorException {
|
||||
String msg = "CA key usage";
|
||||
if (debug != null) {
|
||||
debug.println("KeyChecker.verifyCAKeyUsage() ---checking " + msg
|
||||
+ "...");
|
||||
}
|
||||
|
||||
boolean[] keyUsageBits = cert.getKeyUsage();
|
||||
|
||||
// getKeyUsage returns null if the KeyUsage extension is not present
|
||||
// in the certificate - in which case there is nothing to check
|
||||
if (keyUsageBits == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// throw an exception if the keyCertSign bit is not set
|
||||
if (!keyUsageBits[KEY_CERT_SIGN]) {
|
||||
throw new CertPathValidatorException
|
||||
(msg + " check failed: keyCertSign bit is not set", null,
|
||||
null, -1, PKIXReason.INVALID_KEY_USAGE);
|
||||
}
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("KeyChecker.verifyCAKeyUsage() " + msg
|
||||
+ " verified.");
|
||||
}
|
||||
}
|
||||
}
|
||||
360
jdkSrc/jdk8/sun/security/provider/certpath/OCSP.java
Normal file
360
jdkSrc/jdk8/sun/security/provider/certpath/OCSP.java
Normal file
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertPathValidatorException;
|
||||
import java.security.cert.CertPathValidatorException.BasicReason;
|
||||
import java.security.cert.CRLReason;
|
||||
import java.security.cert.Extension;
|
||||
import java.security.cert.TrustAnchor;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import sun.security.action.GetIntegerAction;
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.validator.Validator;
|
||||
import sun.security.x509.AccessDescription;
|
||||
import sun.security.x509.AuthorityInfoAccessExtension;
|
||||
import sun.security.x509.GeneralName;
|
||||
import sun.security.x509.GeneralNameInterface;
|
||||
import sun.security.x509.PKIXExtensions;
|
||||
import sun.security.x509.URIName;
|
||||
import sun.security.x509.X509CertImpl;
|
||||
|
||||
/**
|
||||
* This is a class that checks the revocation status of a certificate(s) using
|
||||
* OCSP. It is not a PKIXCertPathChecker and therefore can be used outside of
|
||||
* the CertPathValidator framework. It is useful when you want to
|
||||
* just check the revocation status of a certificate, and you don't want to
|
||||
* incur the overhead of validating all of the certificates in the
|
||||
* associated certificate chain.
|
||||
*
|
||||
* @author Sean Mullan
|
||||
*/
|
||||
public final class OCSP {
|
||||
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
|
||||
private static final int DEFAULT_CONNECT_TIMEOUT = 15000;
|
||||
|
||||
/**
|
||||
* Integer value indicating the timeout length, in seconds, to be
|
||||
* used for the OCSP check. A timeout of zero is interpreted as
|
||||
* an infinite timeout.
|
||||
*/
|
||||
private static final int CONNECT_TIMEOUT = initializeTimeout();
|
||||
|
||||
/**
|
||||
* Initialize the timeout length by getting the OCSP timeout
|
||||
* system property. If the property has not been set, or if its
|
||||
* value is negative, set the timeout length to the default.
|
||||
*/
|
||||
private static int initializeTimeout() {
|
||||
Integer tmp = java.security.AccessController.doPrivileged(
|
||||
new GetIntegerAction("com.sun.security.ocsp.timeout"));
|
||||
if (tmp == null || tmp < 0) {
|
||||
return DEFAULT_CONNECT_TIMEOUT;
|
||||
}
|
||||
// Convert to milliseconds, as the system property will be
|
||||
// specified in seconds
|
||||
return tmp * 1000;
|
||||
}
|
||||
|
||||
private OCSP() {}
|
||||
|
||||
|
||||
/**
|
||||
* Obtains the revocation status of a certificate using OCSP.
|
||||
*
|
||||
* @param cert the certificate to be checked
|
||||
* @param issuerCert the issuer certificate
|
||||
* @param responderURI the URI of the OCSP responder
|
||||
* @param responderCert the OCSP responder's certificate
|
||||
* @param date the time the validity of the OCSP responder's certificate
|
||||
* should be checked against. If null, the current time is used.
|
||||
* @return the RevocationStatus
|
||||
* @throws IOException if there is an exception connecting to or
|
||||
* communicating with the OCSP responder
|
||||
* @throws CertPathValidatorException if an exception occurs while
|
||||
* encoding the OCSP Request or validating the OCSP Response
|
||||
*/
|
||||
|
||||
// Called by com.sun.deploy.security.TrustDecider
|
||||
public static RevocationStatus check(X509Certificate cert,
|
||||
X509Certificate issuerCert,
|
||||
URI responderURI,
|
||||
X509Certificate responderCert,
|
||||
Date date)
|
||||
throws IOException, CertPathValidatorException
|
||||
{
|
||||
return check(cert, issuerCert, responderURI, responderCert, date,
|
||||
Collections.<Extension>emptyList(),
|
||||
Validator.VAR_PLUGIN_CODE_SIGNING);
|
||||
}
|
||||
|
||||
|
||||
public static RevocationStatus check(X509Certificate cert,
|
||||
X509Certificate issuerCert, URI responderURI,
|
||||
X509Certificate responderCert, Date date, List<Extension> extensions,
|
||||
String variant)
|
||||
throws IOException, CertPathValidatorException
|
||||
{
|
||||
return check(cert, responderURI, null, issuerCert, responderCert, date,
|
||||
extensions, variant);
|
||||
}
|
||||
|
||||
public static RevocationStatus check(X509Certificate cert,
|
||||
URI responderURI, TrustAnchor anchor, X509Certificate issuerCert,
|
||||
X509Certificate responderCert, Date date,
|
||||
List<Extension> extensions, String variant)
|
||||
throws IOException, CertPathValidatorException
|
||||
{
|
||||
CertId certId;
|
||||
try {
|
||||
X509CertImpl certImpl = X509CertImpl.toImpl(cert);
|
||||
certId = new CertId(issuerCert, certImpl.getSerialNumberObject());
|
||||
} catch (CertificateException | IOException e) {
|
||||
throw new CertPathValidatorException
|
||||
("Exception while encoding OCSPRequest", e);
|
||||
}
|
||||
OCSPResponse ocspResponse = check(Collections.singletonList(certId),
|
||||
responderURI, new OCSPResponse.IssuerInfo(anchor, issuerCert),
|
||||
responderCert, date, extensions, variant);
|
||||
return (RevocationStatus) ocspResponse.getSingleResponse(certId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the revocation status of a list of certificates using OCSP.
|
||||
*
|
||||
* @param certIds the CertIds to be checked
|
||||
* @param responderURI the URI of the OCSP responder
|
||||
* @param issuerInfo the issuer's certificate and/or subject and public key
|
||||
* @param responderCert the OCSP responder's certificate
|
||||
* @param date the time the validity of the OCSP responder's certificate
|
||||
* should be checked against. If null, the current time is used.
|
||||
* @param extensions zero or more OCSP extensions to be included in the
|
||||
* request. If no extensions are requested, an empty {@code List} must
|
||||
* be used. A {@code null} value is not allowed.
|
||||
* @return the OCSPResponse
|
||||
* @throws IOException if there is an exception connecting to or
|
||||
* communicating with the OCSP responder
|
||||
* @throws CertPathValidatorException if an exception occurs while
|
||||
* encoding the OCSP Request or validating the OCSP Response
|
||||
*/
|
||||
static OCSPResponse check(List<CertId> certIds, URI responderURI,
|
||||
OCSPResponse.IssuerInfo issuerInfo,
|
||||
X509Certificate responderCert, Date date,
|
||||
List<Extension> extensions, String variant)
|
||||
throws IOException, CertPathValidatorException
|
||||
{
|
||||
byte[] nonce = null;
|
||||
for (Extension ext : extensions) {
|
||||
if (ext.getId().equals(PKIXExtensions.OCSPNonce_Id.toString())) {
|
||||
nonce = ext.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
OCSPResponse ocspResponse = null;
|
||||
try {
|
||||
byte[] response = getOCSPBytes(certIds, responderURI, extensions);
|
||||
ocspResponse = new OCSPResponse(response);
|
||||
|
||||
// verify the response
|
||||
ocspResponse.verify(certIds, issuerInfo, responderCert, date,
|
||||
nonce, variant);
|
||||
} catch (IOException ioe) {
|
||||
throw new CertPathValidatorException(
|
||||
"Unable to determine revocation status due to network error",
|
||||
ioe, null, -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
|
||||
}
|
||||
|
||||
return ocspResponse;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send an OCSP request, then read and return the OCSP response bytes.
|
||||
*
|
||||
* @param certIds the CertIds to be checked
|
||||
* @param responderURI the URI of the OCSP responder
|
||||
* @param extensions zero or more OCSP extensions to be included in the
|
||||
* request. If no extensions are requested, an empty {@code List} must
|
||||
* be used. A {@code null} value is not allowed.
|
||||
*
|
||||
* @return the OCSP response bytes
|
||||
*
|
||||
* @throws IOException if there is an exception connecting to or
|
||||
* communicating with the OCSP responder
|
||||
*/
|
||||
public static byte[] getOCSPBytes(List<CertId> certIds, URI responderURI,
|
||||
List<Extension> extensions) throws IOException {
|
||||
OCSPRequest request = new OCSPRequest(certIds, extensions);
|
||||
byte[] bytes = request.encodeBytes();
|
||||
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
byte[] response = null;
|
||||
|
||||
try {
|
||||
URL url = responderURI.toURL();
|
||||
if (debug != null) {
|
||||
debug.println("connecting to OCSP service at: " + url);
|
||||
}
|
||||
HttpURLConnection con = (HttpURLConnection)url.openConnection();
|
||||
con.setConnectTimeout(CONNECT_TIMEOUT);
|
||||
con.setReadTimeout(CONNECT_TIMEOUT);
|
||||
con.setDoOutput(true);
|
||||
con.setDoInput(true);
|
||||
con.setRequestMethod("POST");
|
||||
con.setRequestProperty
|
||||
("Content-type", "application/ocsp-request");
|
||||
con.setRequestProperty
|
||||
("Content-length", String.valueOf(bytes.length));
|
||||
out = con.getOutputStream();
|
||||
out.write(bytes);
|
||||
out.flush();
|
||||
// Check the response
|
||||
if (debug != null &&
|
||||
con.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
||||
debug.println("Received HTTP error: " + con.getResponseCode()
|
||||
+ " - " + con.getResponseMessage());
|
||||
}
|
||||
in = con.getInputStream();
|
||||
int contentLength = con.getContentLength();
|
||||
if (contentLength == -1) {
|
||||
contentLength = Integer.MAX_VALUE;
|
||||
}
|
||||
response = new byte[contentLength > 2048 ? 2048 : contentLength];
|
||||
int total = 0;
|
||||
while (total < contentLength) {
|
||||
int count = in.read(response, total, response.length - total);
|
||||
if (count < 0)
|
||||
break;
|
||||
|
||||
total += count;
|
||||
if (total >= response.length && total < contentLength) {
|
||||
response = Arrays.copyOf(response, total * 2);
|
||||
}
|
||||
}
|
||||
response = Arrays.copyOf(response, total);
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException ioe) {
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException ioe) {
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URI of the OCSP Responder as specified in the
|
||||
* certificate's Authority Information Access extension, or null if
|
||||
* not specified.
|
||||
*
|
||||
* @param cert the certificate
|
||||
* @return the URI of the OCSP Responder, or null if not specified
|
||||
*/
|
||||
// Called by com.sun.deploy.security.TrustDecider
|
||||
public static URI getResponderURI(X509Certificate cert) {
|
||||
try {
|
||||
return getResponderURI(X509CertImpl.toImpl(cert));
|
||||
} catch (CertificateException ce) {
|
||||
// treat this case as if the cert had no extension
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static URI getResponderURI(X509CertImpl certImpl) {
|
||||
|
||||
// Examine the certificate's AuthorityInfoAccess extension
|
||||
AuthorityInfoAccessExtension aia =
|
||||
certImpl.getAuthorityInfoAccessExtension();
|
||||
if (aia == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<AccessDescription> descriptions = aia.getAccessDescriptions();
|
||||
for (AccessDescription description : descriptions) {
|
||||
if (description.getAccessMethod().equals(
|
||||
AccessDescription.Ad_OCSP_Id)) {
|
||||
|
||||
GeneralName generalName = description.getAccessLocation();
|
||||
if (generalName.getType() == GeneralNameInterface.NAME_URI) {
|
||||
URIName uri = (URIName) generalName.getName();
|
||||
return uri.getURI();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Revocation Status of a certificate.
|
||||
*/
|
||||
public static interface RevocationStatus {
|
||||
public enum CertStatus { GOOD, REVOKED, UNKNOWN };
|
||||
|
||||
/**
|
||||
* Returns the revocation status.
|
||||
*/
|
||||
CertStatus getCertStatus();
|
||||
/**
|
||||
* Returns the time when the certificate was revoked, or null
|
||||
* if it has not been revoked.
|
||||
*/
|
||||
Date getRevocationTime();
|
||||
/**
|
||||
* Returns the reason the certificate was revoked, or null if it
|
||||
* has not been revoked.
|
||||
*/
|
||||
CRLReason getRevocationReason();
|
||||
|
||||
/**
|
||||
* Returns a Map of additional extensions.
|
||||
*/
|
||||
Map<String, Extension> getSingleExtensions();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import sun.security.x509.Extension;
|
||||
import sun.security.x509.PKIXExtensions;
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.util.DerValue;
|
||||
|
||||
/**
|
||||
* Represent the OCSP Nonce Extension.
|
||||
* This extension, if present, provides a nonce value in OCSP requests
|
||||
* and responses. This will cryptographically bind requests and responses
|
||||
* and help to prevent replay attacks (see RFC 6960, section 4.4.1).
|
||||
*
|
||||
* @see Extension
|
||||
*/
|
||||
public final class OCSPNonceExtension extends Extension {
|
||||
|
||||
/**
|
||||
* Attribute name.
|
||||
*/
|
||||
private static final String EXTENSION_NAME = "OCSPNonce";
|
||||
private byte[] nonceData = null;
|
||||
|
||||
/**
|
||||
* Create an {@code OCSPNonceExtension} by providing the nonce length.
|
||||
* The criticality is set to false, and the OID for the extension will
|
||||
* be the value defined by "id-pkix-ocsp-nonce" from RFC 6960.
|
||||
*
|
||||
* @param length the number of random bytes composing the nonce
|
||||
*
|
||||
* @throws IOException if any errors happen during encoding of the
|
||||
* extension.
|
||||
* @throws IllegalArgumentException if length is not a positive integer.
|
||||
*/
|
||||
public OCSPNonceExtension(int length) throws IOException {
|
||||
this(false, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@code OCSPNonceExtension} by providing the nonce length and
|
||||
* criticality setting. The OID for the extension will
|
||||
* be the value defined by "id-pkix-ocsp-nonce" from RFC 6960.
|
||||
*
|
||||
* @param isCritical a boolean flag indicating whether the criticality bit
|
||||
* is set for this extension
|
||||
* @param length the number of random bytes composing the nonce
|
||||
*
|
||||
* @throws IOException if any errors happen during encoding of the
|
||||
* extension.
|
||||
* @throws IllegalArgumentException if length is not a positive integer.
|
||||
*/
|
||||
public OCSPNonceExtension(boolean isCritical, int length)
|
||||
throws IOException {
|
||||
this.extensionId = PKIXExtensions.OCSPNonce_Id;
|
||||
this.critical = isCritical;
|
||||
|
||||
if (length > 0) {
|
||||
SecureRandom rng = new SecureRandom();
|
||||
this.nonceData = new byte[length];
|
||||
rng.nextBytes(nonceData);
|
||||
this.extensionValue = new DerValue(DerValue.tag_OctetString,
|
||||
nonceData).toByteArray();
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Length must be a positive integer");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@code OCSPNonceExtension} by providing a nonce value.
|
||||
* The criticality is set to false, and the OID for the extension will
|
||||
* be the value defined by "id-pkix-ocsp-nonce" from RFC 6960.
|
||||
*
|
||||
* @param incomingNonce The nonce data to be set for the extension. This
|
||||
* must be a non-null array of at least one byte long.
|
||||
*
|
||||
* @throws IOException if any errors happen during encoding of the
|
||||
* extension.
|
||||
* @throws IllegalArgumentException if the incomingNonce length is not a
|
||||
* positive integer.
|
||||
* @throws NullPointerException if the incomingNonce is null.
|
||||
*/
|
||||
public OCSPNonceExtension(byte[] incomingNonce) throws IOException {
|
||||
this(false, incomingNonce);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@code OCSPNonceExtension} by providing a nonce value and
|
||||
* criticality setting. The OID for the extension will
|
||||
* be the value defined by "id-pkix-ocsp-nonce" from RFC 6960.
|
||||
*
|
||||
* @param isCritical a boolean flag indicating whether the criticality bit
|
||||
* is set for this extension
|
||||
* @param incomingNonce The nonce data to be set for the extension. This
|
||||
* must be a non-null array of at least one byte long.
|
||||
*
|
||||
* @throws IOException if any errors happen during encoding of the
|
||||
* extension.
|
||||
* @throws IllegalArgumentException if the incomingNonce length is not a
|
||||
* positive integer.
|
||||
* @throws NullPointerException if the incomingNonce is null.
|
||||
*/
|
||||
public OCSPNonceExtension(boolean isCritical, byte[] incomingNonce)
|
||||
throws IOException {
|
||||
this.extensionId = PKIXExtensions.OCSPNonce_Id;
|
||||
this.critical = isCritical;
|
||||
|
||||
Objects.requireNonNull(incomingNonce, "Nonce data must be non-null");
|
||||
if (incomingNonce.length > 0) {
|
||||
this.nonceData = incomingNonce.clone();
|
||||
this.extensionValue = new DerValue(DerValue.tag_OctetString,
|
||||
nonceData).toByteArray();
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Nonce data must be at least 1 byte in length");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the nonce bytes themselves, without any DER encoding.
|
||||
*
|
||||
* @return A copy of the underlying nonce bytes
|
||||
*/
|
||||
public byte[] getNonceValue() {
|
||||
return nonceData.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a printable representation of the {@code OCSPNonceExtension}.
|
||||
*
|
||||
* @return a string representation of the extension.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(super.toString()).append(EXTENSION_NAME).append(": ");
|
||||
sb.append((nonceData == null) ? "" : Debug.toString(nonceData));
|
||||
sb.append("\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the extension as a {@code String}
|
||||
*
|
||||
* @return the name of the extension
|
||||
*/
|
||||
public String getName() {
|
||||
return EXTENSION_NAME;
|
||||
}
|
||||
}
|
||||
158
jdkSrc/jdk8/sun/security/provider/certpath/OCSPRequest.java
Normal file
158
jdkSrc/jdk8/sun/security/provider/certpath/OCSPRequest.java
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.cert.Extension;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import sun.misc.HexDumpEncoder;
|
||||
import sun.security.util.*;
|
||||
import sun.security.x509.PKIXExtensions;
|
||||
|
||||
/**
|
||||
* This class can be used to generate an OCSP request and send it over
|
||||
* an output stream. Currently we do not support signing requests.
|
||||
* The OCSP Request is specified in RFC 2560 and
|
||||
* the ASN.1 definition is as follows:
|
||||
* <pre>
|
||||
*
|
||||
* OCSPRequest ::= SEQUENCE {
|
||||
* tbsRequest TBSRequest,
|
||||
* optionalSignature [0] EXPLICIT Signature OPTIONAL }
|
||||
*
|
||||
* TBSRequest ::= SEQUENCE {
|
||||
* version [0] EXPLICIT Version DEFAULT v1,
|
||||
* requestorName [1] EXPLICIT GeneralName OPTIONAL,
|
||||
* requestList SEQUENCE OF Request,
|
||||
* requestExtensions [2] EXPLICIT Extensions OPTIONAL }
|
||||
*
|
||||
* Signature ::= SEQUENCE {
|
||||
* signatureAlgorithm AlgorithmIdentifier,
|
||||
* signature BIT STRING,
|
||||
* certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL
|
||||
* }
|
||||
*
|
||||
* Version ::= INTEGER { v1(0) }
|
||||
*
|
||||
* Request ::= SEQUENCE {
|
||||
* reqCert CertID,
|
||||
* singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL }
|
||||
*
|
||||
* CertID ::= SEQUENCE {
|
||||
* hashAlgorithm AlgorithmIdentifier,
|
||||
* issuerNameHash OCTET STRING, -- Hash of Issuer's DN
|
||||
* issuerKeyHash OCTET STRING, -- Hash of Issuers public key
|
||||
* serialNumber CertificateSerialNumber
|
||||
* }
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author Ram Marti
|
||||
*/
|
||||
|
||||
class OCSPRequest {
|
||||
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
private static final boolean dump = debug != null && Debug.isOn("ocsp");
|
||||
|
||||
// List of request CertIds
|
||||
private final List<CertId> certIds;
|
||||
private final List<Extension> extensions;
|
||||
private byte[] nonce;
|
||||
|
||||
/*
|
||||
* Constructs an OCSPRequest. This constructor is used
|
||||
* to construct an unsigned OCSP Request for a single user cert.
|
||||
*/
|
||||
OCSPRequest(CertId certId) {
|
||||
this(Collections.singletonList(certId));
|
||||
}
|
||||
|
||||
OCSPRequest(List<CertId> certIds) {
|
||||
this.certIds = certIds;
|
||||
this.extensions = Collections.<Extension>emptyList();
|
||||
}
|
||||
|
||||
OCSPRequest(List<CertId> certIds, List<Extension> extensions) {
|
||||
this.certIds = certIds;
|
||||
this.extensions = extensions;
|
||||
}
|
||||
|
||||
byte[] encodeBytes() throws IOException {
|
||||
|
||||
// encode tbsRequest
|
||||
DerOutputStream tmp = new DerOutputStream();
|
||||
DerOutputStream requestsOut = new DerOutputStream();
|
||||
for (CertId certId : certIds) {
|
||||
DerOutputStream certIdOut = new DerOutputStream();
|
||||
certId.encode(certIdOut);
|
||||
requestsOut.write(DerValue.tag_Sequence, certIdOut);
|
||||
}
|
||||
|
||||
tmp.write(DerValue.tag_Sequence, requestsOut);
|
||||
if (!extensions.isEmpty()) {
|
||||
DerOutputStream extOut = new DerOutputStream();
|
||||
for (Extension ext : extensions) {
|
||||
ext.encode(extOut);
|
||||
if (ext.getId().equals(
|
||||
PKIXExtensions.OCSPNonce_Id.toString())) {
|
||||
nonce = ext.getValue();
|
||||
}
|
||||
}
|
||||
DerOutputStream extsOut = new DerOutputStream();
|
||||
extsOut.write(DerValue.tag_Sequence, extOut);
|
||||
tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte)2), extsOut);
|
||||
}
|
||||
|
||||
DerOutputStream tbsRequest = new DerOutputStream();
|
||||
tbsRequest.write(DerValue.tag_Sequence, tmp);
|
||||
|
||||
// OCSPRequest without the signature
|
||||
DerOutputStream ocspRequest = new DerOutputStream();
|
||||
ocspRequest.write(DerValue.tag_Sequence, tbsRequest);
|
||||
|
||||
byte[] bytes = ocspRequest.toByteArray();
|
||||
|
||||
if (dump) {
|
||||
HexDumpEncoder hexEnc = new HexDumpEncoder();
|
||||
debug.println("OCSPRequest bytes...\n\n" +
|
||||
hexEnc.encode(bytes) + "\n");
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
List<CertId> getCertIds() {
|
||||
return certIds;
|
||||
}
|
||||
|
||||
byte[] getNonce() {
|
||||
return nonce;
|
||||
}
|
||||
}
|
||||
1079
jdkSrc/jdk8/sun/security/provider/certpath/OCSPResponse.java
Normal file
1079
jdkSrc/jdk8/sun/security/provider/certpath/OCSPResponse.java
Normal file
File diff suppressed because it is too large
Load Diff
350
jdkSrc/jdk8/sun/security/provider/certpath/PKIX.java
Normal file
350
jdkSrc/jdk8/sun/security/provider/certpath/PKIX.java
Normal file
@@ -0,0 +1,350 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.PublicKey;
|
||||
import java.security.Timestamp;
|
||||
import java.security.cert.*;
|
||||
import java.security.interfaces.DSAPublicKey;
|
||||
import java.util.*;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.validator.Validator;
|
||||
|
||||
/**
|
||||
* Common utility methods and classes used by the PKIX CertPathValidator and
|
||||
* CertPathBuilder implementation.
|
||||
*/
|
||||
class PKIX {
|
||||
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
|
||||
private PKIX() { }
|
||||
|
||||
static boolean isDSAPublicKeyWithoutParams(PublicKey publicKey) {
|
||||
return (publicKey instanceof DSAPublicKey &&
|
||||
((DSAPublicKey)publicKey).getParams() == null);
|
||||
}
|
||||
|
||||
static ValidatorParams checkParams(CertPath cp, CertPathParameters params)
|
||||
throws InvalidAlgorithmParameterException
|
||||
{
|
||||
if (!(params instanceof PKIXParameters)) {
|
||||
throw new InvalidAlgorithmParameterException("inappropriate "
|
||||
+ "params, must be an instance of PKIXParameters");
|
||||
}
|
||||
return new ValidatorParams(cp, (PKIXParameters)params);
|
||||
}
|
||||
|
||||
static BuilderParams checkBuilderParams(CertPathParameters params)
|
||||
throws InvalidAlgorithmParameterException
|
||||
{
|
||||
if (!(params instanceof PKIXBuilderParameters)) {
|
||||
throw new InvalidAlgorithmParameterException("inappropriate "
|
||||
+ "params, must be an instance of PKIXBuilderParameters");
|
||||
}
|
||||
return new BuilderParams((PKIXBuilderParameters)params);
|
||||
}
|
||||
|
||||
/**
|
||||
* PKIXParameters that are shared by the PKIX CertPathValidator
|
||||
* implementation. Provides additional functionality and avoids
|
||||
* unnecessary cloning.
|
||||
*/
|
||||
static class ValidatorParams {
|
||||
private final PKIXParameters params;
|
||||
private CertPath certPath;
|
||||
private List<PKIXCertPathChecker> checkers;
|
||||
private List<CertStore> stores;
|
||||
private boolean gotDate;
|
||||
private Date date;
|
||||
private Set<String> policies;
|
||||
private boolean gotConstraints;
|
||||
private CertSelector constraints;
|
||||
private Set<TrustAnchor> anchors;
|
||||
private List<X509Certificate> certs;
|
||||
private Timestamp timestamp;
|
||||
private Date timestampDate;
|
||||
private String variant = Validator.VAR_GENERIC;
|
||||
|
||||
ValidatorParams(CertPath cp, PKIXParameters params)
|
||||
throws InvalidAlgorithmParameterException
|
||||
{
|
||||
this(params);
|
||||
if (!cp.getType().equals("X.509") && !cp.getType().equals("X509")) {
|
||||
throw new InvalidAlgorithmParameterException("inappropriate "
|
||||
+ "CertPath type specified, must be X.509 or X509");
|
||||
}
|
||||
this.certPath = cp;
|
||||
}
|
||||
|
||||
ValidatorParams(PKIXParameters params)
|
||||
throws InvalidAlgorithmParameterException
|
||||
{
|
||||
if (params instanceof PKIXExtendedParameters) {
|
||||
timestamp = ((PKIXExtendedParameters) params).getTimestamp();
|
||||
variant = ((PKIXExtendedParameters) params).getVariant();
|
||||
}
|
||||
|
||||
this.anchors = params.getTrustAnchors();
|
||||
// Make sure that none of the trust anchors include name constraints
|
||||
// (not supported).
|
||||
for (TrustAnchor anchor : this.anchors) {
|
||||
if (anchor.getNameConstraints() != null) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("name constraints in trust anchor not supported");
|
||||
}
|
||||
}
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
CertPath certPath() {
|
||||
return certPath;
|
||||
}
|
||||
// called by CertPathBuilder after path has been built
|
||||
void setCertPath(CertPath cp) {
|
||||
this.certPath = cp;
|
||||
}
|
||||
List<X509Certificate> certificates() {
|
||||
if (certs == null) {
|
||||
if (certPath == null) {
|
||||
certs = Collections.emptyList();
|
||||
} else {
|
||||
// Reverse the ordering for validation so that the target
|
||||
// cert is the last certificate
|
||||
@SuppressWarnings("unchecked")
|
||||
List<X509Certificate> xc = new ArrayList<>
|
||||
((List<X509Certificate>)certPath.getCertificates());
|
||||
Collections.reverse(xc);
|
||||
certs = xc;
|
||||
}
|
||||
}
|
||||
return certs;
|
||||
}
|
||||
List<PKIXCertPathChecker> certPathCheckers() {
|
||||
if (checkers == null)
|
||||
checkers = params.getCertPathCheckers();
|
||||
return checkers;
|
||||
}
|
||||
List<CertStore> certStores() {
|
||||
if (stores == null)
|
||||
stores = params.getCertStores();
|
||||
return stores;
|
||||
}
|
||||
// The date() param is used when enforcing the validity period
|
||||
// of certificates and when checking the time period of revocation data.
|
||||
// The main difference between the date() and timestamp() method is
|
||||
// that the date() method only uses the timestamp (if specified)
|
||||
// for certificates in a code signer's chain.
|
||||
Date date() {
|
||||
if (!gotDate) {
|
||||
// Use timestamp if checking signed code that is
|
||||
// timestamped, otherwise use date parameter.
|
||||
// Note that TSA server certificates do not use the
|
||||
// timestamp, which means that an expired TSA certificate
|
||||
// is considered a validation failure. This policy means
|
||||
// that signed and timestamped code is valid until the TSA
|
||||
// certificate expires (assuming all other checks are valid).
|
||||
if (timestamp != null &&
|
||||
(variant.equals(Validator.VAR_CODE_SIGNING) ||
|
||||
variant.equals(Validator.VAR_PLUGIN_CODE_SIGNING))) {
|
||||
date = timestamp.getTimestamp();
|
||||
} else {
|
||||
date = params.getDate();
|
||||
if (date == null)
|
||||
date = new Date();
|
||||
}
|
||||
gotDate = true;
|
||||
}
|
||||
return date;
|
||||
}
|
||||
Set<String> initialPolicies() {
|
||||
if (policies == null)
|
||||
policies = params.getInitialPolicies();
|
||||
return policies;
|
||||
}
|
||||
CertSelector targetCertConstraints() {
|
||||
if (!gotConstraints) {
|
||||
constraints = params.getTargetCertConstraints();
|
||||
gotConstraints = true;
|
||||
}
|
||||
return constraints;
|
||||
}
|
||||
Set<TrustAnchor> trustAnchors() {
|
||||
return anchors;
|
||||
}
|
||||
boolean revocationEnabled() {
|
||||
return params.isRevocationEnabled();
|
||||
}
|
||||
boolean policyMappingInhibited() {
|
||||
return params.isPolicyMappingInhibited();
|
||||
}
|
||||
boolean explicitPolicyRequired() {
|
||||
return params.isExplicitPolicyRequired();
|
||||
}
|
||||
boolean policyQualifiersRejected() {
|
||||
return params.getPolicyQualifiersRejected();
|
||||
}
|
||||
String sigProvider() { return params.getSigProvider(); }
|
||||
boolean anyPolicyInhibited() { return params.isAnyPolicyInhibited(); }
|
||||
|
||||
// in rare cases we need access to the original params, for example
|
||||
// in order to clone CertPathCheckers before building a new chain
|
||||
PKIXParameters getPKIXParameters() {
|
||||
return params;
|
||||
}
|
||||
|
||||
String variant() {
|
||||
return variant;
|
||||
}
|
||||
// The timestamp() param is passed as the date param when creating an
|
||||
// AlgorithmChecker. An AlgorithmChecker always uses the timestamp
|
||||
// if specified in order to enforce the denyAfter constraint.
|
||||
Date timestamp() {
|
||||
// return timestamp date if set, otherwise use date parameter
|
||||
if (timestampDate == null) {
|
||||
timestampDate = (timestamp != null)
|
||||
? timestamp.getTimestamp() : date();
|
||||
}
|
||||
return timestampDate;
|
||||
}
|
||||
}
|
||||
|
||||
static class BuilderParams extends ValidatorParams {
|
||||
private PKIXBuilderParameters params;
|
||||
private List<CertStore> stores;
|
||||
private X500Principal targetSubject;
|
||||
|
||||
BuilderParams(PKIXBuilderParameters params)
|
||||
throws InvalidAlgorithmParameterException
|
||||
{
|
||||
super(params);
|
||||
checkParams(params);
|
||||
}
|
||||
private void checkParams(PKIXBuilderParameters params)
|
||||
throws InvalidAlgorithmParameterException
|
||||
{
|
||||
CertSelector sel = targetCertConstraints();
|
||||
if (!(sel instanceof X509CertSelector)) {
|
||||
throw new InvalidAlgorithmParameterException("the "
|
||||
+ "targetCertConstraints parameter must be an "
|
||||
+ "X509CertSelector");
|
||||
}
|
||||
this.params = params;
|
||||
this.targetSubject = getTargetSubject(
|
||||
certStores(), (X509CertSelector)targetCertConstraints());
|
||||
}
|
||||
@Override List<CertStore> certStores() {
|
||||
if (stores == null) {
|
||||
// reorder CertStores so that local CertStores are tried first
|
||||
stores = new ArrayList<>(params.getCertStores());
|
||||
Collections.sort(stores, new CertStoreComparator());
|
||||
}
|
||||
return stores;
|
||||
}
|
||||
int maxPathLength() { return params.getMaxPathLength(); }
|
||||
PKIXBuilderParameters params() { return params; }
|
||||
X500Principal targetSubject() { return targetSubject; }
|
||||
|
||||
/**
|
||||
* Returns the target subject DN from the first X509Certificate that
|
||||
* is fetched that matches the specified X509CertSelector.
|
||||
*/
|
||||
private static X500Principal getTargetSubject(List<CertStore> stores,
|
||||
X509CertSelector sel)
|
||||
throws InvalidAlgorithmParameterException
|
||||
{
|
||||
X500Principal subject = sel.getSubject();
|
||||
if (subject != null) {
|
||||
return subject;
|
||||
}
|
||||
X509Certificate cert = sel.getCertificate();
|
||||
if (cert != null) {
|
||||
subject = cert.getSubjectX500Principal();
|
||||
}
|
||||
if (subject != null) {
|
||||
return subject;
|
||||
}
|
||||
for (CertStore store : stores) {
|
||||
try {
|
||||
Collection<? extends Certificate> certs =
|
||||
(Collection<? extends Certificate>)
|
||||
store.getCertificates(sel);
|
||||
if (!certs.isEmpty()) {
|
||||
X509Certificate xc =
|
||||
(X509Certificate)certs.iterator().next();
|
||||
return xc.getSubjectX500Principal();
|
||||
}
|
||||
} catch (CertStoreException e) {
|
||||
// ignore but log it
|
||||
if (debug != null) {
|
||||
debug.println("BuilderParams.getTargetSubjectDN: " +
|
||||
"non-fatal exception retrieving certs: " + e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Could not determine unique target subject");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A CertStoreException with additional information about the type of
|
||||
* CertStore that generated the exception.
|
||||
*/
|
||||
static class CertStoreTypeException extends CertStoreException {
|
||||
private static final long serialVersionUID = 7463352639238322556L;
|
||||
|
||||
private final String type;
|
||||
|
||||
CertStoreTypeException(String type, CertStoreException cse) {
|
||||
super(cse.getMessage(), cse.getCause());
|
||||
this.type = type;
|
||||
}
|
||||
String getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparator that orders CertStores so that local CertStores come before
|
||||
* remote CertStores.
|
||||
*/
|
||||
private static class CertStoreComparator implements Comparator<CertStore> {
|
||||
@Override
|
||||
public int compare(CertStore store1, CertStore store2) {
|
||||
if (store1.getType().equals("Collection") ||
|
||||
store1.getCertStoreParameters() instanceof
|
||||
CollectionCertStoreParameters) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.cert.*;
|
||||
import java.util.*;
|
||||
|
||||
import sun.security.provider.certpath.PKIX.ValidatorParams;
|
||||
import sun.security.x509.X509CertImpl;
|
||||
import sun.security.util.Debug;
|
||||
|
||||
/**
|
||||
* This class implements the PKIX validation algorithm for certification
|
||||
* paths consisting exclusively of <code>X509Certificates</code>. It uses
|
||||
* the specified input parameter set (which must be a
|
||||
* <code>PKIXParameters</code> object).
|
||||
*
|
||||
* @since 1.4
|
||||
* @author Yassir Elley
|
||||
*/
|
||||
public final class PKIXCertPathValidator extends CertPathValidatorSpi {
|
||||
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public PKIXCertPathValidator() {}
|
||||
|
||||
@Override
|
||||
public CertPathChecker engineGetRevocationChecker() {
|
||||
return new RevocationChecker();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a certification path consisting exclusively of
|
||||
* <code>X509Certificate</code>s using the PKIX validation algorithm,
|
||||
* which uses the specified input parameter set.
|
||||
* The input parameter set must be a <code>PKIXParameters</code> object.
|
||||
*
|
||||
* @param cp the X509 certification path
|
||||
* @param params the input PKIX parameter set
|
||||
* @return the result
|
||||
* @throws CertPathValidatorException if cert path does not validate.
|
||||
* @throws InvalidAlgorithmParameterException if the specified
|
||||
* parameters are inappropriate for this CertPathValidator
|
||||
*/
|
||||
@Override
|
||||
public CertPathValidatorResult engineValidate(CertPath cp,
|
||||
CertPathParameters params)
|
||||
throws CertPathValidatorException, InvalidAlgorithmParameterException
|
||||
{
|
||||
ValidatorParams valParams = PKIX.checkParams(cp, params);
|
||||
return validate(valParams);
|
||||
}
|
||||
|
||||
private static PKIXCertPathValidatorResult validate(ValidatorParams params)
|
||||
throws CertPathValidatorException
|
||||
{
|
||||
if (debug != null)
|
||||
debug.println("PKIXCertPathValidator.engineValidate()...");
|
||||
|
||||
// Retrieve the first certificate in the certpath
|
||||
// (to be used later in pre-screening)
|
||||
AdaptableX509CertSelector selector = null;
|
||||
List<X509Certificate> certList = params.certificates();
|
||||
if (!certList.isEmpty()) {
|
||||
selector = new AdaptableX509CertSelector();
|
||||
X509Certificate firstCert = certList.get(0);
|
||||
// check trusted certificate's subject
|
||||
selector.setSubject(firstCert.getIssuerX500Principal());
|
||||
/*
|
||||
* Facilitate certification path construction with authority
|
||||
* key identifier and subject key identifier.
|
||||
*/
|
||||
try {
|
||||
X509CertImpl firstCertImpl = X509CertImpl.toImpl(firstCert);
|
||||
selector.setSkiAndSerialNumber(
|
||||
firstCertImpl.getAuthorityKeyIdentifierExtension());
|
||||
} catch (CertificateException | IOException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
CertPathValidatorException lastException = null;
|
||||
|
||||
// We iterate through the set of trust anchors until we find
|
||||
// one that works at which time we stop iterating
|
||||
for (TrustAnchor anchor : params.trustAnchors()) {
|
||||
X509Certificate trustedCert = anchor.getTrustedCert();
|
||||
if (trustedCert != null) {
|
||||
// if this trust anchor is not worth trying,
|
||||
// we move on to the next one
|
||||
if (selector != null && !selector.match(trustedCert)) {
|
||||
if (debug != null) {
|
||||
debug.println("NO - don't try this trustedCert");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("YES - try this trustedCert");
|
||||
debug.println("anchor.getTrustedCert()."
|
||||
+ "getSubjectX500Principal() = "
|
||||
+ trustedCert.getSubjectX500Principal());
|
||||
}
|
||||
} else {
|
||||
if (debug != null) {
|
||||
debug.println("PKIXCertPathValidator.engineValidate(): "
|
||||
+ "anchor.getTrustedCert() == null");
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return validate(anchor, params);
|
||||
} catch (CertPathValidatorException cpe) {
|
||||
// remember this exception
|
||||
lastException = cpe;
|
||||
}
|
||||
}
|
||||
|
||||
// could not find a trust anchor that verified
|
||||
// (a) if we did a validation and it failed, use that exception
|
||||
if (lastException != null) {
|
||||
throw lastException;
|
||||
}
|
||||
// (b) otherwise, generate new exception
|
||||
throw new CertPathValidatorException
|
||||
("Path does not chain with any of the trust anchors",
|
||||
null, null, -1, PKIXReason.NO_TRUST_ANCHOR);
|
||||
}
|
||||
|
||||
private static PKIXCertPathValidatorResult validate(TrustAnchor anchor,
|
||||
ValidatorParams params)
|
||||
throws CertPathValidatorException
|
||||
{
|
||||
// check if anchor is untrusted
|
||||
UntrustedChecker untrustedChecker = new UntrustedChecker();
|
||||
X509Certificate anchorCert = anchor.getTrustedCert();
|
||||
if (anchorCert != null) {
|
||||
untrustedChecker.check(anchorCert);
|
||||
}
|
||||
|
||||
int certPathLen = params.certificates().size();
|
||||
|
||||
// create PKIXCertPathCheckers
|
||||
List<PKIXCertPathChecker> certPathCheckers = new ArrayList<>();
|
||||
// add standard checkers that we will be using
|
||||
certPathCheckers.add(untrustedChecker);
|
||||
certPathCheckers.add(new AlgorithmChecker(anchor, null,
|
||||
params.timestamp(), params.variant()));
|
||||
certPathCheckers.add(new KeyChecker(certPathLen,
|
||||
params.targetCertConstraints()));
|
||||
certPathCheckers.add(new ConstraintsChecker(certPathLen));
|
||||
PolicyNodeImpl rootNode =
|
||||
new PolicyNodeImpl(null, PolicyChecker.ANY_POLICY, null, false,
|
||||
Collections.singleton(PolicyChecker.ANY_POLICY),
|
||||
false);
|
||||
PolicyChecker pc = new PolicyChecker(params.initialPolicies(),
|
||||
certPathLen,
|
||||
params.explicitPolicyRequired(),
|
||||
params.policyMappingInhibited(),
|
||||
params.anyPolicyInhibited(),
|
||||
params.policyQualifiersRejected(),
|
||||
rootNode);
|
||||
certPathCheckers.add(pc);
|
||||
|
||||
BasicChecker bc = new BasicChecker(anchor, params.date(),
|
||||
params.sigProvider(), false);
|
||||
certPathCheckers.add(bc);
|
||||
|
||||
boolean revCheckerAdded = false;
|
||||
List<PKIXCertPathChecker> checkers = params.certPathCheckers();
|
||||
for (PKIXCertPathChecker checker : checkers) {
|
||||
if (checker instanceof PKIXRevocationChecker) {
|
||||
if (revCheckerAdded) {
|
||||
throw new CertPathValidatorException(
|
||||
"Only one PKIXRevocationChecker can be specified");
|
||||
}
|
||||
revCheckerAdded = true;
|
||||
// if it's our own, initialize it
|
||||
if (checker instanceof RevocationChecker) {
|
||||
((RevocationChecker)checker).init(anchor, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
// only add a RevocationChecker if revocation is enabled and
|
||||
// a PKIXRevocationChecker has not already been added
|
||||
if (params.revocationEnabled() && !revCheckerAdded) {
|
||||
certPathCheckers.add(new RevocationChecker(anchor, params));
|
||||
}
|
||||
// add user-specified checkers
|
||||
certPathCheckers.addAll(checkers);
|
||||
|
||||
PKIXMasterCertPathValidator.validate(params.certPath(),
|
||||
params.certificates(),
|
||||
certPathCheckers);
|
||||
|
||||
return new PKIXCertPathValidatorResult(anchor, pc.getPolicyTree(),
|
||||
bc.getPublicKey());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.Timestamp;
|
||||
import java.security.cert.CertSelector;
|
||||
import java.security.cert.CertStore;
|
||||
import java.security.cert.PKIXBuilderParameters;
|
||||
import java.security.cert.PKIXCertPathChecker;
|
||||
import java.security.cert.TrustAnchor;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* This class is a wrapper for PKIXBuilderParameters so that a Timestamp object
|
||||
* and a string for the variant type, can be passed when doing certpath
|
||||
* checking.
|
||||
*/
|
||||
|
||||
public class PKIXExtendedParameters extends PKIXBuilderParameters {
|
||||
|
||||
private final PKIXBuilderParameters p;
|
||||
private Timestamp jarTimestamp;
|
||||
private final String variant;
|
||||
|
||||
public PKIXExtendedParameters(PKIXBuilderParameters params,
|
||||
Timestamp timestamp, String variant)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
super(params.getTrustAnchors(), null);
|
||||
p = params;
|
||||
jarTimestamp = timestamp;
|
||||
this.variant = variant;
|
||||
}
|
||||
|
||||
public Timestamp getTimestamp() {
|
||||
return jarTimestamp;
|
||||
}
|
||||
public void setTimestamp(Timestamp t) {
|
||||
jarTimestamp = t;
|
||||
}
|
||||
|
||||
public String getVariant() {
|
||||
return variant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDate(Date d) {
|
||||
p.setDate(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCertPathChecker(PKIXCertPathChecker c) {
|
||||
p.addCertPathChecker(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxPathLength(int maxPathLength) {
|
||||
p.setMaxPathLength(maxPathLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxPathLength() {
|
||||
return p.getMaxPathLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return p.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<TrustAnchor> getTrustAnchors() {
|
||||
return p.getTrustAnchors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrustAnchors(Set<TrustAnchor> trustAnchors)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
// To avoid problems with PKIXBuilderParameter's constructors
|
||||
if (p == null) {
|
||||
return;
|
||||
}
|
||||
p.setTrustAnchors(trustAnchors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getInitialPolicies() {
|
||||
return p.getInitialPolicies();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInitialPolicies(Set<String> initialPolicies) {
|
||||
p.setInitialPolicies(initialPolicies);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCertStores(List<CertStore> stores) {
|
||||
p.setCertStores(stores);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCertStore(CertStore store) {
|
||||
p.addCertStore(store);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CertStore> getCertStores() {
|
||||
return p.getCertStores();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRevocationEnabled(boolean val) {
|
||||
p.setRevocationEnabled(val);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRevocationEnabled() {
|
||||
return p.isRevocationEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExplicitPolicyRequired(boolean val) {
|
||||
p.setExplicitPolicyRequired(val);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExplicitPolicyRequired() {
|
||||
return p.isExplicitPolicyRequired();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPolicyMappingInhibited(boolean val) {
|
||||
p.setPolicyMappingInhibited(val);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPolicyMappingInhibited() {
|
||||
return p.isPolicyMappingInhibited();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAnyPolicyInhibited(boolean val) {
|
||||
p.setAnyPolicyInhibited(val);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAnyPolicyInhibited() {
|
||||
return p.isAnyPolicyInhibited();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPolicyQualifiersRejected(boolean qualifiersRejected) {
|
||||
p.setPolicyQualifiersRejected(qualifiersRejected);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getPolicyQualifiersRejected() {
|
||||
return p.getPolicyQualifiersRejected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getDate() {
|
||||
return p.getDate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCertPathCheckers(List<PKIXCertPathChecker> checkers) {
|
||||
p.setCertPathCheckers(checkers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PKIXCertPathChecker> getCertPathCheckers() {
|
||||
return p.getCertPathCheckers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSigProvider() {
|
||||
return p.getSigProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSigProvider(String sigProvider) {
|
||||
p.setSigProvider(sigProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CertSelector getTargetCertConstraints() {
|
||||
return p.getTargetCertConstraints();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTargetCertConstraints(CertSelector selector) {
|
||||
// To avoid problems with PKIXBuilderParameter's constructors
|
||||
if (p == null) {
|
||||
return;
|
||||
}
|
||||
p.setTargetCertConstraints(selector);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import sun.security.util.Debug;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
import java.security.cert.CertPath;
|
||||
import java.security.cert.CertPathValidatorException;
|
||||
import java.security.cert.PKIXCertPathChecker;
|
||||
import java.security.cert.PKIXReason;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
/**
|
||||
* This class is initialized with a list of <code>PKIXCertPathChecker</code>s
|
||||
* and is used to verify the certificates in a <code>CertPath</code> by
|
||||
* feeding each certificate to each <code>PKIXCertPathChecker</code>.
|
||||
*
|
||||
* @since 1.4
|
||||
* @author Yassir Elley
|
||||
*/
|
||||
class PKIXMasterCertPathValidator {
|
||||
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
|
||||
/**
|
||||
* Validates a certification path consisting exclusively of
|
||||
* <code>X509Certificate</code>s using the specified
|
||||
* <code>PKIXCertPathChecker</code>s. It is assumed that the
|
||||
* <code>PKIXCertPathChecker</code>s
|
||||
* have been initialized with any input parameters they may need.
|
||||
*
|
||||
* @param cpOriginal the original X509 CertPath passed in by the user
|
||||
* @param reversedCertList the reversed X509 CertPath (as a List)
|
||||
* @param certPathCheckers the PKIXCertPathCheckers
|
||||
* @throws CertPathValidatorException if cert path does not validate
|
||||
*/
|
||||
static void validate(CertPath cpOriginal,
|
||||
List<X509Certificate> reversedCertList,
|
||||
List<PKIXCertPathChecker> certPathCheckers)
|
||||
throws CertPathValidatorException
|
||||
{
|
||||
// we actually process reversedCertList, but we keep cpOriginal because
|
||||
// we need to return the original certPath when we throw an exception.
|
||||
// we will also need to modify the index appropriately when we
|
||||
// throw an exception.
|
||||
|
||||
int cpSize = reversedCertList.size();
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("--------------------------------------------------"
|
||||
+ "------------");
|
||||
debug.println("Executing PKIX certification path validation "
|
||||
+ "algorithm.");
|
||||
}
|
||||
|
||||
for (int i = 0; i < cpSize; i++) {
|
||||
|
||||
/* The basic loop algorithm is that we get the
|
||||
* current certificate, we verify the current certificate using
|
||||
* information from the previous certificate and from the state,
|
||||
* and we modify the state for the next loop by setting the
|
||||
* current certificate of this loop to be the previous certificate
|
||||
* of the next loop. The state is initialized during first loop.
|
||||
*/
|
||||
X509Certificate currCert = reversedCertList.get(i);
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("Checking cert" + (i+1) + " - Subject: " +
|
||||
currCert.getSubjectX500Principal());
|
||||
}
|
||||
|
||||
Set<String> unresCritExts = currCert.getCriticalExtensionOIDs();
|
||||
if (unresCritExts == null) {
|
||||
unresCritExts = Collections.<String>emptySet();
|
||||
}
|
||||
|
||||
if (debug != null && !unresCritExts.isEmpty()) {
|
||||
StringJoiner joiner = new StringJoiner(", ", "{", "}");
|
||||
for (String oid : unresCritExts) {
|
||||
joiner.add(oid);
|
||||
}
|
||||
debug.println("Set of critical extensions: " +
|
||||
joiner.toString());
|
||||
}
|
||||
|
||||
for (int j = 0; j < certPathCheckers.size(); j++) {
|
||||
|
||||
PKIXCertPathChecker currChecker = certPathCheckers.get(j);
|
||||
if (debug != null) {
|
||||
debug.println("-Using checker" + (j + 1) + " ... [" +
|
||||
currChecker.getClass().getName() + "]");
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
currChecker.init(false);
|
||||
|
||||
try {
|
||||
currChecker.check(currCert, unresCritExts);
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("-checker" + (j + 1) +
|
||||
" validation succeeded");
|
||||
}
|
||||
|
||||
} catch (CertPathValidatorException cpve) {
|
||||
throw new CertPathValidatorException(cpve.getMessage(),
|
||||
(cpve.getCause() != null) ? cpve.getCause() : cpve,
|
||||
cpOriginal, cpSize - (i + 1), cpve.getReason());
|
||||
}
|
||||
}
|
||||
|
||||
if (!unresCritExts.isEmpty()) {
|
||||
throw new CertPathValidatorException("unrecognized " +
|
||||
"critical extension(s)", null, cpOriginal, cpSize-(i+1),
|
||||
PKIXReason.UNRECOGNIZED_CRIT_EXT);
|
||||
}
|
||||
|
||||
if (debug != null)
|
||||
debug.println("\ncert" + (i+1) + " validation succeeded.\n");
|
||||
}
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("Cert path validation succeeded. (PKIX validation "
|
||||
+ "algorithm)");
|
||||
debug.println("-------------------------------------------------"
|
||||
+ "-------------");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.Timestamp;
|
||||
import java.security.cert.CertSelector;
|
||||
import java.security.cert.CertStore;
|
||||
import java.security.cert.PKIXBuilderParameters;
|
||||
import java.security.cert.PKIXCertPathChecker;
|
||||
import java.security.cert.TrustAnchor;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* This class is a wrapper for PKIXBuilderParameters so that a Timestamp object
|
||||
* can be passed alone when PKIXCertPath is checking signed jar files.
|
||||
*/
|
||||
|
||||
public class PKIXTimestampParameters extends PKIXBuilderParameters {
|
||||
|
||||
private final PKIXBuilderParameters p;
|
||||
private Timestamp jarTimestamp;
|
||||
|
||||
public PKIXTimestampParameters(PKIXBuilderParameters params,
|
||||
Timestamp timestamp) throws InvalidAlgorithmParameterException {
|
||||
super(params.getTrustAnchors(), null);
|
||||
p = params;
|
||||
jarTimestamp = timestamp;
|
||||
}
|
||||
|
||||
public Timestamp getTimestamp() {
|
||||
return jarTimestamp;
|
||||
}
|
||||
public void setTimestamp(Timestamp t) {
|
||||
jarTimestamp = t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDate(Date d) {
|
||||
p.setDate(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCertPathChecker(PKIXCertPathChecker c) {
|
||||
p.addCertPathChecker(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxPathLength(int maxPathLength) {
|
||||
p.setMaxPathLength(maxPathLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxPathLength() {
|
||||
return p.getMaxPathLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return p.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<TrustAnchor> getTrustAnchors() {
|
||||
return p.getTrustAnchors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrustAnchors(Set<TrustAnchor> trustAnchors)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
// To avoid problems with PKIXBuilderParameter's constructors
|
||||
if (p == null) {
|
||||
return;
|
||||
}
|
||||
p.setTrustAnchors(trustAnchors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getInitialPolicies() {
|
||||
return p.getInitialPolicies();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInitialPolicies(Set<String> initialPolicies) {
|
||||
p.setInitialPolicies(initialPolicies);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCertStores(List<CertStore> stores) {
|
||||
p.setCertStores(stores);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCertStore(CertStore store) {
|
||||
p.addCertStore(store);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CertStore> getCertStores() {
|
||||
return p.getCertStores();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRevocationEnabled(boolean val) {
|
||||
p.setRevocationEnabled(val);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRevocationEnabled() {
|
||||
return p.isRevocationEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExplicitPolicyRequired(boolean val) {
|
||||
p.setExplicitPolicyRequired(val);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExplicitPolicyRequired() {
|
||||
return p.isExplicitPolicyRequired();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPolicyMappingInhibited(boolean val) {
|
||||
p.setPolicyMappingInhibited(val);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPolicyMappingInhibited() {
|
||||
return p.isPolicyMappingInhibited();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAnyPolicyInhibited(boolean val) {
|
||||
p.setAnyPolicyInhibited(val);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAnyPolicyInhibited() {
|
||||
return p.isAnyPolicyInhibited();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPolicyQualifiersRejected(boolean qualifiersRejected) {
|
||||
p.setPolicyQualifiersRejected(qualifiersRejected);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getPolicyQualifiersRejected() {
|
||||
return p.getPolicyQualifiersRejected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getDate() {
|
||||
return p.getDate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCertPathCheckers(List<PKIXCertPathChecker> checkers) {
|
||||
p.setCertPathCheckers(checkers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PKIXCertPathChecker> getCertPathCheckers() {
|
||||
return p.getCertPathCheckers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSigProvider() {
|
||||
return p.getSigProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSigProvider(String sigProvider) {
|
||||
p.setSigProvider(sigProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CertSelector getTargetCertConstraints() {
|
||||
return p.getTargetCertConstraints();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTargetCertConstraints(CertSelector selector) {
|
||||
// To avoid problems with PKIXBuilderParameter's constructors
|
||||
if (p == null) {
|
||||
return;
|
||||
}
|
||||
p.setTargetCertConstraints(selector);
|
||||
}
|
||||
|
||||
}
|
||||
924
jdkSrc/jdk8/sun/security/provider/certpath/PolicyChecker.java
Normal file
924
jdkSrc/jdk8/sun/security/provider/certpath/PolicyChecker.java
Normal file
@@ -0,0 +1,924 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertPathValidatorException;
|
||||
import java.security.cert.PKIXCertPathChecker;
|
||||
import java.security.cert.PKIXReason;
|
||||
import java.security.cert.PolicyNode;
|
||||
import java.security.cert.PolicyQualifierInfo;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.*;
|
||||
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.x509.CertificatePoliciesExtension;
|
||||
import sun.security.x509.PolicyConstraintsExtension;
|
||||
import sun.security.x509.PolicyMappingsExtension;
|
||||
import sun.security.x509.CertificatePolicyMap;
|
||||
import static sun.security.x509.PKIXExtensions.*;
|
||||
import sun.security.x509.PolicyInformation;
|
||||
import sun.security.x509.X509CertImpl;
|
||||
import sun.security.x509.InhibitAnyPolicyExtension;
|
||||
|
||||
/**
|
||||
* PolicyChecker is a <code>PKIXCertPathChecker</code> that checks policy
|
||||
* information on a PKIX certificate, namely certificate policies, policy
|
||||
* mappings, policy constraints and policy qualifiers.
|
||||
*
|
||||
* @since 1.4
|
||||
* @author Yassir Elley
|
||||
*/
|
||||
class PolicyChecker extends PKIXCertPathChecker {
|
||||
|
||||
private final Set<String> initPolicies;
|
||||
private final int certPathLen;
|
||||
private final boolean expPolicyRequired;
|
||||
private final boolean polMappingInhibited;
|
||||
private final boolean anyPolicyInhibited;
|
||||
private final boolean rejectPolicyQualifiers;
|
||||
private PolicyNodeImpl rootNode;
|
||||
private int explicitPolicy;
|
||||
private int policyMapping;
|
||||
private int inhibitAnyPolicy;
|
||||
private int certIndex;
|
||||
|
||||
private Set<String> supportedExts;
|
||||
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
static final String ANY_POLICY = "2.5.29.32.0";
|
||||
|
||||
/**
|
||||
* Constructs a Policy Checker.
|
||||
*
|
||||
* @param initialPolicies Set of initial policies
|
||||
* @param certPathLen length of the certification path to be checked
|
||||
* @param expPolicyRequired true if explicit policy is required
|
||||
* @param polMappingInhibited true if policy mapping is inhibited
|
||||
* @param anyPolicyInhibited true if the ANY_POLICY OID should be inhibited
|
||||
* @param rejectPolicyQualifiers true if pol qualifiers are to be rejected
|
||||
* @param rootNode the initial root node of the valid policy tree
|
||||
*/
|
||||
PolicyChecker(Set<String> initialPolicies, int certPathLen,
|
||||
boolean expPolicyRequired, boolean polMappingInhibited,
|
||||
boolean anyPolicyInhibited, boolean rejectPolicyQualifiers,
|
||||
PolicyNodeImpl rootNode)
|
||||
{
|
||||
if (initialPolicies.isEmpty()) {
|
||||
// if no initialPolicies are specified by user, set
|
||||
// initPolicies to be anyPolicy by default
|
||||
this.initPolicies = new HashSet<String>(1);
|
||||
this.initPolicies.add(ANY_POLICY);
|
||||
} else {
|
||||
this.initPolicies = new HashSet<String>(initialPolicies);
|
||||
}
|
||||
this.certPathLen = certPathLen;
|
||||
this.expPolicyRequired = expPolicyRequired;
|
||||
this.polMappingInhibited = polMappingInhibited;
|
||||
this.anyPolicyInhibited = anyPolicyInhibited;
|
||||
this.rejectPolicyQualifiers = rejectPolicyQualifiers;
|
||||
this.rootNode = rootNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the internal state of the checker from parameters
|
||||
* specified in the constructor
|
||||
*
|
||||
* @param forward a boolean indicating whether this checker should be
|
||||
* initialized capable of building in the forward direction
|
||||
* @throws CertPathValidatorException if user wants to enable forward
|
||||
* checking and forward checking is not supported.
|
||||
*/
|
||||
@Override
|
||||
public void init(boolean forward) throws CertPathValidatorException {
|
||||
if (forward) {
|
||||
throw new CertPathValidatorException
|
||||
("forward checking not supported");
|
||||
}
|
||||
|
||||
certIndex = 1;
|
||||
explicitPolicy = (expPolicyRequired ? 0 : certPathLen + 1);
|
||||
policyMapping = (polMappingInhibited ? 0 : certPathLen + 1);
|
||||
inhibitAnyPolicy = (anyPolicyInhibited ? 0 : certPathLen + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if forward checking is supported. Forward checking refers
|
||||
* to the ability of the PKIXCertPathChecker to perform its checks
|
||||
* when presented with certificates in the forward direction (from
|
||||
* target to anchor).
|
||||
*
|
||||
* @return true if forward checking is supported, false otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean isForwardCheckingSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an immutable Set of the OID strings for the extensions that
|
||||
* the PKIXCertPathChecker supports (i.e. recognizes, is able to
|
||||
* process), or null if no extensions are
|
||||
* supported. All OID strings that a PKIXCertPathChecker might
|
||||
* possibly be able to process should be included.
|
||||
*
|
||||
* @return the Set of extensions supported by this PKIXCertPathChecker,
|
||||
* or null if no extensions are supported
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getSupportedExtensions() {
|
||||
if (supportedExts == null) {
|
||||
supportedExts = new HashSet<String>(4);
|
||||
supportedExts.add(CertificatePolicies_Id.toString());
|
||||
supportedExts.add(PolicyMappings_Id.toString());
|
||||
supportedExts.add(PolicyConstraints_Id.toString());
|
||||
supportedExts.add(InhibitAnyPolicy_Id.toString());
|
||||
supportedExts = Collections.unmodifiableSet(supportedExts);
|
||||
}
|
||||
return supportedExts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the policy processing checks on the certificate using its
|
||||
* internal state.
|
||||
*
|
||||
* @param cert the Certificate to be processed
|
||||
* @param unresCritExts the unresolved critical extensions
|
||||
* @throws CertPathValidatorException if the certificate does not verify
|
||||
*/
|
||||
@Override
|
||||
public void check(Certificate cert, Collection<String> unresCritExts)
|
||||
throws CertPathValidatorException
|
||||
{
|
||||
// now do the policy checks
|
||||
checkPolicy((X509Certificate) cert);
|
||||
|
||||
if (unresCritExts != null && !unresCritExts.isEmpty()) {
|
||||
unresCritExts.remove(CertificatePolicies_Id.toString());
|
||||
unresCritExts.remove(PolicyMappings_Id.toString());
|
||||
unresCritExts.remove(PolicyConstraints_Id.toString());
|
||||
unresCritExts.remove(InhibitAnyPolicy_Id.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to run through all the checks.
|
||||
*
|
||||
* @param currCert the certificate to be processed
|
||||
* @exception CertPathValidatorException Exception thrown if
|
||||
* the certificate does not verify
|
||||
*/
|
||||
private void checkPolicy(X509Certificate currCert)
|
||||
throws CertPathValidatorException
|
||||
{
|
||||
String msg = "certificate policies";
|
||||
if (debug != null) {
|
||||
debug.println("PolicyChecker.checkPolicy() ---checking " + msg
|
||||
+ "...");
|
||||
debug.println("PolicyChecker.checkPolicy() certIndex = "
|
||||
+ certIndex);
|
||||
debug.println("PolicyChecker.checkPolicy() BEFORE PROCESSING: "
|
||||
+ "explicitPolicy = " + explicitPolicy);
|
||||
debug.println("PolicyChecker.checkPolicy() BEFORE PROCESSING: "
|
||||
+ "policyMapping = " + policyMapping);
|
||||
debug.println("PolicyChecker.checkPolicy() BEFORE PROCESSING: "
|
||||
+ "inhibitAnyPolicy = " + inhibitAnyPolicy);
|
||||
debug.println("PolicyChecker.checkPolicy() BEFORE PROCESSING: "
|
||||
+ "policyTree = " + rootNode);
|
||||
}
|
||||
|
||||
X509CertImpl currCertImpl = null;
|
||||
try {
|
||||
currCertImpl = X509CertImpl.toImpl(currCert);
|
||||
} catch (CertificateException ce) {
|
||||
throw new CertPathValidatorException(ce);
|
||||
}
|
||||
|
||||
boolean finalCert = (certIndex == certPathLen);
|
||||
|
||||
rootNode = processPolicies(certIndex, initPolicies, explicitPolicy,
|
||||
policyMapping, inhibitAnyPolicy, rejectPolicyQualifiers, rootNode,
|
||||
currCertImpl, finalCert);
|
||||
|
||||
if (!finalCert) {
|
||||
explicitPolicy = mergeExplicitPolicy(explicitPolicy, currCertImpl,
|
||||
finalCert);
|
||||
policyMapping = mergePolicyMapping(policyMapping, currCertImpl);
|
||||
inhibitAnyPolicy = mergeInhibitAnyPolicy(inhibitAnyPolicy,
|
||||
currCertImpl);
|
||||
}
|
||||
|
||||
certIndex++;
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("PolicyChecker.checkPolicy() AFTER PROCESSING: "
|
||||
+ "explicitPolicy = " + explicitPolicy);
|
||||
debug.println("PolicyChecker.checkPolicy() AFTER PROCESSING: "
|
||||
+ "policyMapping = " + policyMapping);
|
||||
debug.println("PolicyChecker.checkPolicy() AFTER PROCESSING: "
|
||||
+ "inhibitAnyPolicy = " + inhibitAnyPolicy);
|
||||
debug.println("PolicyChecker.checkPolicy() AFTER PROCESSING: "
|
||||
+ "policyTree = " + rootNode);
|
||||
debug.println("PolicyChecker.checkPolicy() " + msg + " verified");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the specified explicitPolicy value with the
|
||||
* requireExplicitPolicy field of the <code>PolicyConstraints</code>
|
||||
* extension obtained from the certificate. An explicitPolicy
|
||||
* value of -1 implies no constraint.
|
||||
*
|
||||
* @param explicitPolicy an integer which indicates if a non-null
|
||||
* valid policy tree is required
|
||||
* @param currCert the Certificate to be processed
|
||||
* @param finalCert a boolean indicating whether currCert is
|
||||
* the final cert in the cert path
|
||||
* @return returns the new explicitPolicy value
|
||||
* @exception CertPathValidatorException Exception thrown if an error
|
||||
* occurs
|
||||
*/
|
||||
static int mergeExplicitPolicy(int explicitPolicy, X509CertImpl currCert,
|
||||
boolean finalCert) throws CertPathValidatorException
|
||||
{
|
||||
if ((explicitPolicy > 0) && !X509CertImpl.isSelfIssued(currCert)) {
|
||||
explicitPolicy--;
|
||||
}
|
||||
|
||||
try {
|
||||
PolicyConstraintsExtension polConstExt
|
||||
= currCert.getPolicyConstraintsExtension();
|
||||
if (polConstExt == null)
|
||||
return explicitPolicy;
|
||||
int require =
|
||||
polConstExt.get(PolicyConstraintsExtension.REQUIRE).intValue();
|
||||
if (debug != null) {
|
||||
debug.println("PolicyChecker.mergeExplicitPolicy() "
|
||||
+ "require Index from cert = " + require);
|
||||
}
|
||||
if (!finalCert) {
|
||||
if (require != -1) {
|
||||
if ((explicitPolicy == -1) || (require < explicitPolicy)) {
|
||||
explicitPolicy = require;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (require == 0)
|
||||
explicitPolicy = require;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (debug != null) {
|
||||
debug.println("PolicyChecker.mergeExplicitPolicy "
|
||||
+ "unexpected exception");
|
||||
e.printStackTrace();
|
||||
}
|
||||
throw new CertPathValidatorException(e);
|
||||
}
|
||||
|
||||
return explicitPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the specified policyMapping value with the
|
||||
* inhibitPolicyMapping field of the <code>PolicyConstraints</code>
|
||||
* extension obtained from the certificate. A policyMapping
|
||||
* value of -1 implies no constraint.
|
||||
*
|
||||
* @param policyMapping an integer which indicates if policy mapping
|
||||
* is inhibited
|
||||
* @param currCert the Certificate to be processed
|
||||
* @return returns the new policyMapping value
|
||||
* @exception CertPathValidatorException Exception thrown if an error
|
||||
* occurs
|
||||
*/
|
||||
static int mergePolicyMapping(int policyMapping, X509CertImpl currCert)
|
||||
throws CertPathValidatorException
|
||||
{
|
||||
if ((policyMapping > 0) && !X509CertImpl.isSelfIssued(currCert)) {
|
||||
policyMapping--;
|
||||
}
|
||||
|
||||
try {
|
||||
PolicyConstraintsExtension polConstExt
|
||||
= currCert.getPolicyConstraintsExtension();
|
||||
if (polConstExt == null)
|
||||
return policyMapping;
|
||||
|
||||
int inhibit =
|
||||
polConstExt.get(PolicyConstraintsExtension.INHIBIT).intValue();
|
||||
if (debug != null)
|
||||
debug.println("PolicyChecker.mergePolicyMapping() "
|
||||
+ "inhibit Index from cert = " + inhibit);
|
||||
|
||||
if (inhibit != -1) {
|
||||
if ((policyMapping == -1) || (inhibit < policyMapping)) {
|
||||
policyMapping = inhibit;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (debug != null) {
|
||||
debug.println("PolicyChecker.mergePolicyMapping "
|
||||
+ "unexpected exception");
|
||||
e.printStackTrace();
|
||||
}
|
||||
throw new CertPathValidatorException(e);
|
||||
}
|
||||
|
||||
return policyMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the specified inhibitAnyPolicy value with the
|
||||
* SkipCerts value of the InhibitAnyPolicy
|
||||
* extension obtained from the certificate.
|
||||
*
|
||||
* @param inhibitAnyPolicy an integer which indicates whether
|
||||
* "any-policy" is considered a match
|
||||
* @param currCert the Certificate to be processed
|
||||
* @return returns the new inhibitAnyPolicy value
|
||||
* @exception CertPathValidatorException Exception thrown if an error
|
||||
* occurs
|
||||
*/
|
||||
static int mergeInhibitAnyPolicy(int inhibitAnyPolicy,
|
||||
X509CertImpl currCert) throws CertPathValidatorException
|
||||
{
|
||||
if ((inhibitAnyPolicy > 0) && !X509CertImpl.isSelfIssued(currCert)) {
|
||||
inhibitAnyPolicy--;
|
||||
}
|
||||
|
||||
try {
|
||||
InhibitAnyPolicyExtension inhAnyPolExt = (InhibitAnyPolicyExtension)
|
||||
currCert.getExtension(InhibitAnyPolicy_Id);
|
||||
if (inhAnyPolExt == null)
|
||||
return inhibitAnyPolicy;
|
||||
|
||||
int skipCerts =
|
||||
inhAnyPolExt.get(InhibitAnyPolicyExtension.SKIP_CERTS).intValue();
|
||||
if (debug != null)
|
||||
debug.println("PolicyChecker.mergeInhibitAnyPolicy() "
|
||||
+ "skipCerts Index from cert = " + skipCerts);
|
||||
|
||||
if (skipCerts != -1) {
|
||||
if (skipCerts < inhibitAnyPolicy) {
|
||||
inhibitAnyPolicy = skipCerts;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (debug != null) {
|
||||
debug.println("PolicyChecker.mergeInhibitAnyPolicy "
|
||||
+ "unexpected exception");
|
||||
e.printStackTrace();
|
||||
}
|
||||
throw new CertPathValidatorException(e);
|
||||
}
|
||||
|
||||
return inhibitAnyPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes certificate policies in the certificate.
|
||||
*
|
||||
* @param certIndex the index of the certificate
|
||||
* @param initPolicies the initial policies required by the user
|
||||
* @param explicitPolicy an integer which indicates if a non-null
|
||||
* valid policy tree is required
|
||||
* @param policyMapping an integer which indicates if policy
|
||||
* mapping is inhibited
|
||||
* @param inhibitAnyPolicy an integer which indicates whether
|
||||
* "any-policy" is considered a match
|
||||
* @param rejectPolicyQualifiers a boolean indicating whether the
|
||||
* user wants to reject policies that have qualifiers
|
||||
* @param origRootNode the root node of the valid policy tree
|
||||
* @param currCert the Certificate to be processed
|
||||
* @param finalCert a boolean indicating whether currCert is the final
|
||||
* cert in the cert path
|
||||
* @return the root node of the valid policy tree after modification
|
||||
* @exception CertPathValidatorException Exception thrown if an
|
||||
* error occurs while processing policies.
|
||||
*/
|
||||
static PolicyNodeImpl processPolicies(int certIndex, Set<String> initPolicies,
|
||||
int explicitPolicy, int policyMapping, int inhibitAnyPolicy,
|
||||
boolean rejectPolicyQualifiers, PolicyNodeImpl origRootNode,
|
||||
X509CertImpl currCert, boolean finalCert)
|
||||
throws CertPathValidatorException
|
||||
{
|
||||
boolean policiesCritical = false;
|
||||
List<PolicyInformation> policyInfo;
|
||||
PolicyNodeImpl rootNode = null;
|
||||
Set<PolicyQualifierInfo> anyQuals = new HashSet<>();
|
||||
|
||||
if (origRootNode == null)
|
||||
rootNode = null;
|
||||
else
|
||||
rootNode = origRootNode.copyTree();
|
||||
|
||||
// retrieve policyOIDs from currCert
|
||||
CertificatePoliciesExtension currCertPolicies
|
||||
= currCert.getCertificatePoliciesExtension();
|
||||
|
||||
// PKIX: Section 6.1.3: Step (d)
|
||||
if ((currCertPolicies != null) && (rootNode != null)) {
|
||||
policiesCritical = currCertPolicies.isCritical();
|
||||
if (debug != null)
|
||||
debug.println("PolicyChecker.processPolicies() "
|
||||
+ "policiesCritical = " + policiesCritical);
|
||||
|
||||
try {
|
||||
policyInfo = currCertPolicies.get(CertificatePoliciesExtension.POLICIES);
|
||||
} catch (IOException ioe) {
|
||||
throw new CertPathValidatorException("Exception while "
|
||||
+ "retrieving policyOIDs", ioe);
|
||||
}
|
||||
|
||||
if (debug != null)
|
||||
debug.println("PolicyChecker.processPolicies() "
|
||||
+ "rejectPolicyQualifiers = " + rejectPolicyQualifiers);
|
||||
|
||||
boolean foundAnyPolicy = false;
|
||||
|
||||
// process each policy in cert
|
||||
for (PolicyInformation curPolInfo : policyInfo) {
|
||||
String curPolicy =
|
||||
curPolInfo.getPolicyIdentifier().getIdentifier().toString();
|
||||
|
||||
if (curPolicy.equals(ANY_POLICY)) {
|
||||
foundAnyPolicy = true;
|
||||
anyQuals = curPolInfo.getPolicyQualifiers();
|
||||
} else {
|
||||
// PKIX: Section 6.1.3: Step (d)(1)
|
||||
if (debug != null)
|
||||
debug.println("PolicyChecker.processPolicies() "
|
||||
+ "processing policy: " + curPolicy);
|
||||
|
||||
// retrieve policy qualifiers from cert
|
||||
Set<PolicyQualifierInfo> pQuals =
|
||||
curPolInfo.getPolicyQualifiers();
|
||||
|
||||
// reject cert if we find critical policy qualifiers and
|
||||
// the policyQualifiersRejected flag is set in the params
|
||||
if (!pQuals.isEmpty() && rejectPolicyQualifiers &&
|
||||
policiesCritical) {
|
||||
throw new CertPathValidatorException(
|
||||
"critical policy qualifiers present in certificate",
|
||||
null, null, -1, PKIXReason.INVALID_POLICY);
|
||||
}
|
||||
|
||||
// PKIX: Section 6.1.3: Step (d)(1)(i)
|
||||
boolean foundMatch = processParents(certIndex,
|
||||
policiesCritical, rejectPolicyQualifiers, rootNode,
|
||||
curPolicy, pQuals, false);
|
||||
|
||||
if (!foundMatch) {
|
||||
// PKIX: Section 6.1.3: Step (d)(1)(ii)
|
||||
processParents(certIndex, policiesCritical,
|
||||
rejectPolicyQualifiers, rootNode, curPolicy,
|
||||
pQuals, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PKIX: Section 6.1.3: Step (d)(2)
|
||||
if (foundAnyPolicy) {
|
||||
if ((inhibitAnyPolicy > 0) ||
|
||||
(!finalCert && X509CertImpl.isSelfIssued(currCert))) {
|
||||
if (debug != null) {
|
||||
debug.println("PolicyChecker.processPolicies() "
|
||||
+ "processing policy: " + ANY_POLICY);
|
||||
}
|
||||
processParents(certIndex, policiesCritical,
|
||||
rejectPolicyQualifiers, rootNode, ANY_POLICY, anyQuals,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
// PKIX: Section 6.1.3: Step (d)(3)
|
||||
rootNode.prune(certIndex);
|
||||
if (!rootNode.getChildren().hasNext()) {
|
||||
rootNode = null;
|
||||
}
|
||||
} else if (currCertPolicies == null) {
|
||||
if (debug != null)
|
||||
debug.println("PolicyChecker.processPolicies() "
|
||||
+ "no policies present in cert");
|
||||
// PKIX: Section 6.1.3: Step (e)
|
||||
rootNode = null;
|
||||
}
|
||||
|
||||
// We delay PKIX: Section 6.1.3: Step (f) to the end
|
||||
// because the code that follows may delete some nodes
|
||||
// resulting in a null tree
|
||||
if (rootNode != null) {
|
||||
if (!finalCert) {
|
||||
// PKIX: Section 6.1.4: Steps (a)-(b)
|
||||
rootNode = processPolicyMappings(currCert, certIndex,
|
||||
policyMapping, rootNode, policiesCritical, anyQuals);
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, we optimize the PKIX algorithm by
|
||||
// removing those nodes which would later have
|
||||
// been removed by PKIX: Section 6.1.5: Step (g)(iii)
|
||||
|
||||
if ((rootNode != null) && (!initPolicies.contains(ANY_POLICY))
|
||||
&& (currCertPolicies != null)) {
|
||||
rootNode = removeInvalidNodes(rootNode, certIndex,
|
||||
initPolicies, currCertPolicies);
|
||||
|
||||
// PKIX: Section 6.1.5: Step (g)(iii)
|
||||
if ((rootNode != null) && finalCert) {
|
||||
// rewrite anyPolicy leaf nodes (see method comments)
|
||||
rootNode = rewriteLeafNodes(certIndex, initPolicies, rootNode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (finalCert) {
|
||||
// PKIX: Section 6.1.5: Steps (a) and (b)
|
||||
explicitPolicy = mergeExplicitPolicy(explicitPolicy, currCert,
|
||||
finalCert);
|
||||
}
|
||||
|
||||
// PKIX: Section 6.1.3: Step (f)
|
||||
// verify that either explicit policy is greater than 0 or
|
||||
// the valid_policy_tree is not equal to NULL
|
||||
|
||||
if ((explicitPolicy == 0) && (rootNode == null)) {
|
||||
throw new CertPathValidatorException
|
||||
("non-null policy tree required and policy tree is null",
|
||||
null, null, -1, PKIXReason.INVALID_POLICY);
|
||||
}
|
||||
|
||||
return rootNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrite leaf nodes at the end of validation as described in RFC 5280
|
||||
* section 6.1.5: Step (g)(iii). Leaf nodes with anyPolicy are replaced
|
||||
* by nodes explicitly representing initial policies not already
|
||||
* represented by leaf nodes.
|
||||
*
|
||||
* This method should only be called when processing the final cert
|
||||
* and if the policy tree is not null and initial policies is not
|
||||
* anyPolicy.
|
||||
*
|
||||
* @param certIndex the depth of the tree
|
||||
* @param initPolicies Set of user specified initial policies
|
||||
* @param rootNode the root of the policy tree
|
||||
*/
|
||||
private static PolicyNodeImpl rewriteLeafNodes(int certIndex,
|
||||
Set<String> initPolicies, PolicyNodeImpl rootNode) {
|
||||
Set<PolicyNodeImpl> anyNodes =
|
||||
rootNode.getPolicyNodesValid(certIndex, ANY_POLICY);
|
||||
if (anyNodes.isEmpty()) {
|
||||
return rootNode;
|
||||
}
|
||||
PolicyNodeImpl anyNode = anyNodes.iterator().next();
|
||||
PolicyNodeImpl parentNode = (PolicyNodeImpl)anyNode.getParent();
|
||||
parentNode.deleteChild(anyNode);
|
||||
// see if there are any initialPolicies not represented by leaf nodes
|
||||
Set<String> initial = new HashSet<>(initPolicies);
|
||||
for (PolicyNodeImpl node : rootNode.getPolicyNodes(certIndex)) {
|
||||
initial.remove(node.getValidPolicy());
|
||||
}
|
||||
if (initial.isEmpty()) {
|
||||
// we deleted the anyPolicy node and have nothing to re-add,
|
||||
// so we need to prune the tree
|
||||
rootNode.prune(certIndex);
|
||||
if (rootNode.getChildren().hasNext() == false) {
|
||||
rootNode = null;
|
||||
}
|
||||
} else {
|
||||
boolean anyCritical = anyNode.isCritical();
|
||||
Set<PolicyQualifierInfo> anyQualifiers =
|
||||
anyNode.getPolicyQualifiers();
|
||||
for (String policy : initial) {
|
||||
Set<String> expectedPolicies = Collections.singleton(policy);
|
||||
PolicyNodeImpl node = new PolicyNodeImpl(parentNode, policy,
|
||||
anyQualifiers, anyCritical, expectedPolicies, false);
|
||||
}
|
||||
}
|
||||
return rootNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the policy nodes of depth (certIndex-1) where curPolicy
|
||||
* is in the expected policy set and creates a new child node
|
||||
* appropriately. If matchAny is true, then a value of ANY_POLICY
|
||||
* in the expected policy set will match any curPolicy. If matchAny
|
||||
* is false, then the expected policy set must exactly contain the
|
||||
* curPolicy to be considered a match. This method returns a boolean
|
||||
* value indicating whether a match was found.
|
||||
*
|
||||
* @param certIndex the index of the certificate whose policy is
|
||||
* being processed
|
||||
* @param policiesCritical a boolean indicating whether the certificate
|
||||
* policies extension is critical
|
||||
* @param rejectPolicyQualifiers a boolean indicating whether the
|
||||
* user wants to reject policies that have qualifiers
|
||||
* @param rootNode the root node of the valid policy tree
|
||||
* @param curPolicy a String representing the policy being processed
|
||||
* @param pQuals the policy qualifiers of the policy being processed or an
|
||||
* empty Set if there are no qualifiers
|
||||
* @param matchAny a boolean indicating whether a value of ANY_POLICY
|
||||
* in the expected policy set will be considered a match
|
||||
* @return a boolean indicating whether a match was found
|
||||
* @exception CertPathValidatorException Exception thrown if error occurs.
|
||||
*/
|
||||
private static boolean processParents(int certIndex,
|
||||
boolean policiesCritical, boolean rejectPolicyQualifiers,
|
||||
PolicyNodeImpl rootNode, String curPolicy,
|
||||
Set<PolicyQualifierInfo> pQuals,
|
||||
boolean matchAny) throws CertPathValidatorException
|
||||
{
|
||||
boolean foundMatch = false;
|
||||
|
||||
if (debug != null)
|
||||
debug.println("PolicyChecker.processParents(): matchAny = "
|
||||
+ matchAny);
|
||||
|
||||
// find matching parents
|
||||
Set<PolicyNodeImpl> parentNodes =
|
||||
rootNode.getPolicyNodesExpected(certIndex - 1,
|
||||
curPolicy, matchAny);
|
||||
|
||||
// for each matching parent, extend policy tree
|
||||
for (PolicyNodeImpl curParent : parentNodes) {
|
||||
if (debug != null)
|
||||
debug.println("PolicyChecker.processParents() "
|
||||
+ "found parent:\n" + curParent.asString());
|
||||
|
||||
foundMatch = true;
|
||||
String curParPolicy = curParent.getValidPolicy();
|
||||
|
||||
PolicyNodeImpl curNode = null;
|
||||
Set<String> curExpPols = null;
|
||||
|
||||
if (curPolicy.equals(ANY_POLICY)) {
|
||||
// do step 2
|
||||
Set<String> parExpPols = curParent.getExpectedPolicies();
|
||||
parentExplicitPolicies:
|
||||
for (String curParExpPol : parExpPols) {
|
||||
|
||||
Iterator<PolicyNodeImpl> childIter =
|
||||
curParent.getChildren();
|
||||
while (childIter.hasNext()) {
|
||||
PolicyNodeImpl childNode = childIter.next();
|
||||
String childPolicy = childNode.getValidPolicy();
|
||||
if (curParExpPol.equals(childPolicy)) {
|
||||
if (debug != null)
|
||||
debug.println(childPolicy + " in parent's "
|
||||
+ "expected policy set already appears in "
|
||||
+ "child node");
|
||||
continue parentExplicitPolicies;
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> expPols = new HashSet<>();
|
||||
expPols.add(curParExpPol);
|
||||
|
||||
curNode = new PolicyNodeImpl
|
||||
(curParent, curParExpPol, pQuals,
|
||||
policiesCritical, expPols, false);
|
||||
}
|
||||
} else {
|
||||
curExpPols = new HashSet<String>();
|
||||
curExpPols.add(curPolicy);
|
||||
|
||||
curNode = new PolicyNodeImpl
|
||||
(curParent, curPolicy, pQuals,
|
||||
policiesCritical, curExpPols, false);
|
||||
}
|
||||
}
|
||||
|
||||
return foundMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes policy mappings in the certificate.
|
||||
*
|
||||
* @param currCert the Certificate to be processed
|
||||
* @param certIndex the index of the current certificate
|
||||
* @param policyMapping an integer which indicates if policy
|
||||
* mapping is inhibited
|
||||
* @param rootNode the root node of the valid policy tree
|
||||
* @param policiesCritical a boolean indicating if the certificate policies
|
||||
* extension is critical
|
||||
* @param anyQuals the qualifiers associated with ANY-POLICY, or an empty
|
||||
* Set if there are no qualifiers associated with ANY-POLICY
|
||||
* @return the root node of the valid policy tree after modification
|
||||
* @exception CertPathValidatorException exception thrown if an error
|
||||
* occurs while processing policy mappings
|
||||
*/
|
||||
private static PolicyNodeImpl processPolicyMappings(X509CertImpl currCert,
|
||||
int certIndex, int policyMapping, PolicyNodeImpl rootNode,
|
||||
boolean policiesCritical, Set<PolicyQualifierInfo> anyQuals)
|
||||
throws CertPathValidatorException
|
||||
{
|
||||
PolicyMappingsExtension polMappingsExt
|
||||
= currCert.getPolicyMappingsExtension();
|
||||
|
||||
if (polMappingsExt == null)
|
||||
return rootNode;
|
||||
|
||||
if (debug != null)
|
||||
debug.println("PolicyChecker.processPolicyMappings() "
|
||||
+ "inside policyMapping check");
|
||||
|
||||
List<CertificatePolicyMap> maps = null;
|
||||
try {
|
||||
maps = polMappingsExt.get(PolicyMappingsExtension.MAP);
|
||||
} catch (IOException e) {
|
||||
if (debug != null) {
|
||||
debug.println("PolicyChecker.processPolicyMappings() "
|
||||
+ "mapping exception");
|
||||
e.printStackTrace();
|
||||
}
|
||||
throw new CertPathValidatorException("Exception while checking "
|
||||
+ "mapping", e);
|
||||
}
|
||||
|
||||
boolean childDeleted = false;
|
||||
for (CertificatePolicyMap polMap : maps) {
|
||||
String issuerDomain
|
||||
= polMap.getIssuerIdentifier().getIdentifier().toString();
|
||||
String subjectDomain
|
||||
= polMap.getSubjectIdentifier().getIdentifier().toString();
|
||||
if (debug != null) {
|
||||
debug.println("PolicyChecker.processPolicyMappings() "
|
||||
+ "issuerDomain = " + issuerDomain);
|
||||
debug.println("PolicyChecker.processPolicyMappings() "
|
||||
+ "subjectDomain = " + subjectDomain);
|
||||
}
|
||||
|
||||
if (issuerDomain.equals(ANY_POLICY)) {
|
||||
throw new CertPathValidatorException
|
||||
("encountered an issuerDomainPolicy of ANY_POLICY",
|
||||
null, null, -1, PKIXReason.INVALID_POLICY);
|
||||
}
|
||||
|
||||
if (subjectDomain.equals(ANY_POLICY)) {
|
||||
throw new CertPathValidatorException
|
||||
("encountered a subjectDomainPolicy of ANY_POLICY",
|
||||
null, null, -1, PKIXReason.INVALID_POLICY);
|
||||
}
|
||||
|
||||
Set<PolicyNodeImpl> validNodes =
|
||||
rootNode.getPolicyNodesValid(certIndex, issuerDomain);
|
||||
if (!validNodes.isEmpty()) {
|
||||
for (PolicyNodeImpl curNode : validNodes) {
|
||||
if ((policyMapping > 0) || (policyMapping == -1)) {
|
||||
curNode.addExpectedPolicy(subjectDomain);
|
||||
} else if (policyMapping == 0) {
|
||||
PolicyNodeImpl parentNode =
|
||||
(PolicyNodeImpl) curNode.getParent();
|
||||
if (debug != null)
|
||||
debug.println("PolicyChecker.processPolicyMappings"
|
||||
+ "() before deleting: policy tree = "
|
||||
+ rootNode);
|
||||
parentNode.deleteChild(curNode);
|
||||
childDeleted = true;
|
||||
if (debug != null)
|
||||
debug.println("PolicyChecker.processPolicyMappings"
|
||||
+ "() after deleting: policy tree = "
|
||||
+ rootNode);
|
||||
}
|
||||
}
|
||||
} else { // no node of depth i has a valid policy
|
||||
if ((policyMapping > 0) || (policyMapping == -1)) {
|
||||
Set<PolicyNodeImpl> validAnyNodes =
|
||||
rootNode.getPolicyNodesValid(certIndex, ANY_POLICY);
|
||||
for (PolicyNodeImpl curAnyNode : validAnyNodes) {
|
||||
PolicyNodeImpl curAnyNodeParent =
|
||||
(PolicyNodeImpl) curAnyNode.getParent();
|
||||
|
||||
Set<String> expPols = new HashSet<>();
|
||||
expPols.add(subjectDomain);
|
||||
|
||||
PolicyNodeImpl curNode = new PolicyNodeImpl
|
||||
(curAnyNodeParent, issuerDomain, anyQuals,
|
||||
policiesCritical, expPols, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (childDeleted) {
|
||||
rootNode.prune(certIndex);
|
||||
if (!rootNode.getChildren().hasNext()) {
|
||||
if (debug != null)
|
||||
debug.println("setting rootNode to null");
|
||||
rootNode = null;
|
||||
}
|
||||
}
|
||||
|
||||
return rootNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes those nodes which do not intersect with the initial policies
|
||||
* specified by the user.
|
||||
*
|
||||
* @param rootNode the root node of the valid policy tree
|
||||
* @param certIndex the index of the certificate being processed
|
||||
* @param initPolicies the Set of policies required by the user
|
||||
* @param currCertPolicies the CertificatePoliciesExtension of the
|
||||
* certificate being processed
|
||||
* @returns the root node of the valid policy tree after modification
|
||||
* @exception CertPathValidatorException Exception thrown if error occurs.
|
||||
*/
|
||||
private static PolicyNodeImpl removeInvalidNodes(PolicyNodeImpl rootNode,
|
||||
int certIndex, Set<String> initPolicies,
|
||||
CertificatePoliciesExtension currCertPolicies)
|
||||
throws CertPathValidatorException
|
||||
{
|
||||
List<PolicyInformation> policyInfo = null;
|
||||
try {
|
||||
policyInfo = currCertPolicies.get(CertificatePoliciesExtension.POLICIES);
|
||||
} catch (IOException ioe) {
|
||||
throw new CertPathValidatorException("Exception while "
|
||||
+ "retrieving policyOIDs", ioe);
|
||||
}
|
||||
|
||||
boolean childDeleted = false;
|
||||
for (PolicyInformation curPolInfo : policyInfo) {
|
||||
String curPolicy =
|
||||
curPolInfo.getPolicyIdentifier().getIdentifier().toString();
|
||||
|
||||
if (debug != null)
|
||||
debug.println("PolicyChecker.processPolicies() "
|
||||
+ "processing policy second time: " + curPolicy);
|
||||
|
||||
Set<PolicyNodeImpl> validNodes =
|
||||
rootNode.getPolicyNodesValid(certIndex, curPolicy);
|
||||
for (PolicyNodeImpl curNode : validNodes) {
|
||||
PolicyNodeImpl parentNode = (PolicyNodeImpl)curNode.getParent();
|
||||
if (parentNode.getValidPolicy().equals(ANY_POLICY)) {
|
||||
if ((!initPolicies.contains(curPolicy)) &&
|
||||
(!curPolicy.equals(ANY_POLICY))) {
|
||||
if (debug != null)
|
||||
debug.println("PolicyChecker.processPolicies() "
|
||||
+ "before deleting: policy tree = " + rootNode);
|
||||
parentNode.deleteChild(curNode);
|
||||
childDeleted = true;
|
||||
if (debug != null)
|
||||
debug.println("PolicyChecker.processPolicies() "
|
||||
+ "after deleting: policy tree = " + rootNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (childDeleted) {
|
||||
rootNode.prune(certIndex);
|
||||
if (!rootNode.getChildren().hasNext()) {
|
||||
rootNode = null;
|
||||
}
|
||||
}
|
||||
|
||||
return rootNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the root node of the valid policy tree, or null if the
|
||||
* valid policy tree is null. Marks each node of the returned tree
|
||||
* immutable and thread-safe.
|
||||
*
|
||||
* @returns the root node of the valid policy tree, or null if
|
||||
* the valid policy tree is null
|
||||
*/
|
||||
PolicyNode getPolicyTree() {
|
||||
if (rootNode == null)
|
||||
return null;
|
||||
else {
|
||||
PolicyNodeImpl policyTree = rootNode.copyTree();
|
||||
policyTree.setImmutable();
|
||||
return policyTree;
|
||||
}
|
||||
}
|
||||
}
|
||||
424
jdkSrc/jdk8/sun/security/provider/certpath/PolicyNodeImpl.java
Normal file
424
jdkSrc/jdk8/sun/security/provider/certpath/PolicyNodeImpl.java
Normal file
@@ -0,0 +1,424 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import java.security.cert.*;
|
||||
|
||||
/**
|
||||
* Implements the <code>PolicyNode</code> interface.
|
||||
* <p>
|
||||
* This class provides an implementation of the <code>PolicyNode</code>
|
||||
* interface, and is used internally to build and search Policy Trees.
|
||||
* While the implementation is mutable during construction, it is immutable
|
||||
* before returning to a client and no mutable public or protected methods
|
||||
* are exposed by this implementation, as per the contract of PolicyNode.
|
||||
*
|
||||
* @since 1.4
|
||||
* @author Seth Proctor
|
||||
* @author Sean Mullan
|
||||
*/
|
||||
final class PolicyNodeImpl implements PolicyNode {
|
||||
|
||||
/**
|
||||
* Use to specify the special policy "Any Policy"
|
||||
*/
|
||||
private static final String ANY_POLICY = "2.5.29.32.0";
|
||||
|
||||
// every node has one parent, and zero or more children
|
||||
private PolicyNodeImpl mParent;
|
||||
private HashSet<PolicyNodeImpl> mChildren;
|
||||
|
||||
// the 4 fields specified by RFC 5280
|
||||
private String mValidPolicy;
|
||||
private HashSet<PolicyQualifierInfo> mQualifierSet;
|
||||
private boolean mCriticalityIndicator;
|
||||
private HashSet<String> mExpectedPolicySet;
|
||||
private boolean mOriginalExpectedPolicySet;
|
||||
|
||||
// the tree depth
|
||||
private int mDepth;
|
||||
// immutability flag
|
||||
private boolean isImmutable = false;
|
||||
|
||||
/**
|
||||
* Constructor which takes a <code>PolicyNodeImpl</code> representing the
|
||||
* parent in the Policy Tree to this node. If null, this is the
|
||||
* root of the tree. The constructor also takes the associated data
|
||||
* for this node, as found in the certificate. It also takes a boolean
|
||||
* argument specifying whether this node is being created as a result
|
||||
* of policy mapping.
|
||||
*
|
||||
* @param parent the PolicyNode above this in the tree, or null if this
|
||||
* node is the tree's root node
|
||||
* @param validPolicy a String representing this node's valid policy OID
|
||||
* @param qualifierSet the Set of qualifiers for this policy
|
||||
* @param criticalityIndicator a boolean representing whether or not the
|
||||
* extension is critical
|
||||
* @param expectedPolicySet a Set of expected policies
|
||||
* @param generatedByPolicyMapping a boolean indicating whether this
|
||||
* node was generated by a policy mapping
|
||||
*/
|
||||
PolicyNodeImpl(PolicyNodeImpl parent, String validPolicy,
|
||||
Set<PolicyQualifierInfo> qualifierSet,
|
||||
boolean criticalityIndicator, Set<String> expectedPolicySet,
|
||||
boolean generatedByPolicyMapping) {
|
||||
mParent = parent;
|
||||
mChildren = new HashSet<PolicyNodeImpl>();
|
||||
|
||||
if (validPolicy != null)
|
||||
mValidPolicy = validPolicy;
|
||||
else
|
||||
mValidPolicy = "";
|
||||
|
||||
if (qualifierSet != null)
|
||||
mQualifierSet = new HashSet<PolicyQualifierInfo>(qualifierSet);
|
||||
else
|
||||
mQualifierSet = new HashSet<PolicyQualifierInfo>();
|
||||
|
||||
mCriticalityIndicator = criticalityIndicator;
|
||||
|
||||
if (expectedPolicySet != null)
|
||||
mExpectedPolicySet = new HashSet<String>(expectedPolicySet);
|
||||
else
|
||||
mExpectedPolicySet = new HashSet<String>();
|
||||
|
||||
mOriginalExpectedPolicySet = !generatedByPolicyMapping;
|
||||
|
||||
// see if we're the root, and act appropriately
|
||||
if (mParent != null) {
|
||||
mDepth = mParent.getDepth() + 1;
|
||||
mParent.addChild(this);
|
||||
} else {
|
||||
mDepth = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternate constructor which makes a new node with the policy data
|
||||
* in an existing <code>PolicyNodeImpl</code>.
|
||||
*
|
||||
* @param parent a PolicyNode that's the new parent of the node, or
|
||||
* null if this is the root node
|
||||
* @param node a PolicyNode containing the policy data to copy
|
||||
*/
|
||||
PolicyNodeImpl(PolicyNodeImpl parent, PolicyNodeImpl node) {
|
||||
this(parent, node.mValidPolicy, node.mQualifierSet,
|
||||
node.mCriticalityIndicator, node.mExpectedPolicySet, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PolicyNode getParent() {
|
||||
return mParent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<PolicyNodeImpl> getChildren() {
|
||||
return Collections.unmodifiableSet(mChildren).iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDepth() {
|
||||
return mDepth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValidPolicy() {
|
||||
return mValidPolicy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<PolicyQualifierInfo> getPolicyQualifiers() {
|
||||
return Collections.unmodifiableSet(mQualifierSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getExpectedPolicies() {
|
||||
return Collections.unmodifiableSet(mExpectedPolicySet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCritical() {
|
||||
return mCriticalityIndicator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a printable representation of the PolicyNode.
|
||||
* Starting at the node on which this method is called,
|
||||
* it recurses through the tree and prints out each node.
|
||||
*
|
||||
* @return a String describing the contents of the Policy Node
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buffer = new StringBuilder(this.asString());
|
||||
|
||||
for (PolicyNodeImpl node : mChildren) {
|
||||
buffer.append(node);
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
// private methods and package private operations
|
||||
|
||||
boolean isImmutable() {
|
||||
return isImmutable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the immutability flag of this node and all of its children
|
||||
* to true.
|
||||
*/
|
||||
void setImmutable() {
|
||||
if (isImmutable)
|
||||
return;
|
||||
for (PolicyNodeImpl node : mChildren) {
|
||||
node.setImmutable();
|
||||
}
|
||||
isImmutable = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private method sets a child node. This is called from the child's
|
||||
* constructor.
|
||||
*
|
||||
* @param child new <code>PolicyNodeImpl</code> child node
|
||||
*/
|
||||
private void addChild(PolicyNodeImpl child) {
|
||||
if (isImmutable) {
|
||||
throw new IllegalStateException("PolicyNode is immutable");
|
||||
}
|
||||
mChildren.add(child);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an expectedPolicy to the expected policy set.
|
||||
* If this is the original expected policy set initialized
|
||||
* by the constructor, then the expected policy set is cleared
|
||||
* before the expected policy is added.
|
||||
*
|
||||
* @param expectedPolicy a String representing an expected policy.
|
||||
*/
|
||||
void addExpectedPolicy(String expectedPolicy) {
|
||||
if (isImmutable) {
|
||||
throw new IllegalStateException("PolicyNode is immutable");
|
||||
}
|
||||
if (mOriginalExpectedPolicySet) {
|
||||
mExpectedPolicySet.clear();
|
||||
mOriginalExpectedPolicySet = false;
|
||||
}
|
||||
mExpectedPolicySet.add(expectedPolicy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all paths which don't reach the specified depth.
|
||||
*
|
||||
* @param depth an int representing the desired minimum depth of all paths
|
||||
*/
|
||||
void prune(int depth) {
|
||||
if (isImmutable)
|
||||
throw new IllegalStateException("PolicyNode is immutable");
|
||||
|
||||
// if we have no children, we can't prune below us...
|
||||
if (mChildren.size() == 0)
|
||||
return;
|
||||
|
||||
Iterator<PolicyNodeImpl> it = mChildren.iterator();
|
||||
while (it.hasNext()) {
|
||||
PolicyNodeImpl node = it.next();
|
||||
node.prune(depth);
|
||||
// now that we've called prune on the child, see if we should
|
||||
// remove it from the tree
|
||||
if ((node.mChildren.size() == 0) && (depth > mDepth + 1))
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the specified child node of this node, if it exists.
|
||||
*
|
||||
* @param childNode the child node to be deleted
|
||||
*/
|
||||
void deleteChild(PolicyNode childNode) {
|
||||
if (isImmutable) {
|
||||
throw new IllegalStateException("PolicyNode is immutable");
|
||||
}
|
||||
mChildren.remove(childNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the tree, without copying the policy-related data,
|
||||
* rooted at the node on which this was called.
|
||||
*
|
||||
* @return a copy of the tree
|
||||
*/
|
||||
PolicyNodeImpl copyTree() {
|
||||
return copyTree(null);
|
||||
}
|
||||
|
||||
private PolicyNodeImpl copyTree(PolicyNodeImpl parent) {
|
||||
PolicyNodeImpl newNode = new PolicyNodeImpl(parent, this);
|
||||
|
||||
for (PolicyNodeImpl node : mChildren) {
|
||||
node.copyTree(newNode);
|
||||
}
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all nodes at the specified depth in the tree.
|
||||
*
|
||||
* @param depth an int representing the depth of the desired nodes
|
||||
* @return a <code>Set</code> of all nodes at the specified depth
|
||||
*/
|
||||
Set<PolicyNodeImpl> getPolicyNodes(int depth) {
|
||||
Set<PolicyNodeImpl> set = new HashSet<>();
|
||||
getPolicyNodes(depth, set);
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all nodes at depth depth to set and return the Set.
|
||||
* Internal recursion helper.
|
||||
*/
|
||||
private void getPolicyNodes(int depth, Set<PolicyNodeImpl> set) {
|
||||
// if we've reached the desired depth, then return ourself
|
||||
if (mDepth == depth) {
|
||||
set.add(this);
|
||||
} else {
|
||||
for (PolicyNodeImpl node : mChildren) {
|
||||
node.getPolicyNodes(depth, set);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all nodes at the specified depth whose expected_policy_set
|
||||
* contains the specified expected OID (if matchAny is false)
|
||||
* or the special OID "any value" (if matchAny is true).
|
||||
*
|
||||
* @param depth an int representing the desired depth
|
||||
* @param expectedOID a String encoding the valid OID to match
|
||||
* @param matchAny a boolean indicating whether an expected_policy_set
|
||||
* containing ANY_POLICY should be considered a match
|
||||
* @return a Set of matched <code>PolicyNode</code>s
|
||||
*/
|
||||
Set<PolicyNodeImpl> getPolicyNodesExpected(int depth,
|
||||
String expectedOID, boolean matchAny) {
|
||||
|
||||
if (expectedOID.equals(ANY_POLICY)) {
|
||||
return getPolicyNodes(depth);
|
||||
} else {
|
||||
return getPolicyNodesExpectedHelper(depth, expectedOID, matchAny);
|
||||
}
|
||||
}
|
||||
|
||||
private Set<PolicyNodeImpl> getPolicyNodesExpectedHelper(int depth,
|
||||
String expectedOID, boolean matchAny) {
|
||||
|
||||
HashSet<PolicyNodeImpl> set = new HashSet<>();
|
||||
|
||||
if (mDepth < depth) {
|
||||
for (PolicyNodeImpl node : mChildren) {
|
||||
set.addAll(node.getPolicyNodesExpectedHelper(depth,
|
||||
expectedOID,
|
||||
matchAny));
|
||||
}
|
||||
} else {
|
||||
if (matchAny) {
|
||||
if (mExpectedPolicySet.contains(ANY_POLICY))
|
||||
set.add(this);
|
||||
} else {
|
||||
if (mExpectedPolicySet.contains(expectedOID))
|
||||
set.add(this);
|
||||
}
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all nodes at the specified depth that contains the
|
||||
* specified valid OID
|
||||
*
|
||||
* @param depth an int representing the desired depth
|
||||
* @param validOID a String encoding the valid OID to match
|
||||
* @return a Set of matched <code>PolicyNode</code>s
|
||||
*/
|
||||
Set<PolicyNodeImpl> getPolicyNodesValid(int depth, String validOID) {
|
||||
HashSet<PolicyNodeImpl> set = new HashSet<>();
|
||||
|
||||
if (mDepth < depth) {
|
||||
for (PolicyNodeImpl node : mChildren) {
|
||||
set.addAll(node.getPolicyNodesValid(depth, validOID));
|
||||
}
|
||||
} else {
|
||||
if (mValidPolicy.equals(validOID))
|
||||
set.add(this);
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
private static String policyToString(String oid) {
|
||||
if (oid.equals(ANY_POLICY)) {
|
||||
return "anyPolicy";
|
||||
} else {
|
||||
return oid;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints out some data on this node.
|
||||
*/
|
||||
String asString() {
|
||||
if (mParent == null) {
|
||||
return "anyPolicy ROOT\n";
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0, n = getDepth(); i < n; i++) {
|
||||
sb.append(" ");
|
||||
}
|
||||
sb.append(policyToString(getValidPolicy()));
|
||||
sb.append(" CRIT: ");
|
||||
sb.append(isCritical());
|
||||
sb.append(" EP: ");
|
||||
for (String policy : getExpectedPolicies()) {
|
||||
sb.append(policyToString(policy));
|
||||
sb.append(" ");
|
||||
}
|
||||
sb.append(" (");
|
||||
sb.append(getDepth());
|
||||
sb.append(")\n");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
315
jdkSrc/jdk8/sun/security/provider/certpath/ResponderId.java
Normal file
315
jdkSrc/jdk8/sun/security/provider/certpath/ResponderId.java
Normal file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.io.IOException;
|
||||
import java.security.PublicKey;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
import sun.security.x509.KeyIdentifier;
|
||||
import sun.security.util.DerValue;
|
||||
|
||||
/**
|
||||
* Class for ResponderId entities as described in RFC6960. ResponderId objects
|
||||
* are used to uniquely identify OCSP responders.
|
||||
* <p>
|
||||
* The RFC 6960 defines a ResponderID structure as:
|
||||
* <pre>
|
||||
* ResponderID ::= CHOICE {
|
||||
* byName [1] Name,
|
||||
* byKey [2] KeyHash }
|
||||
*
|
||||
* KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key
|
||||
* (excluding the tag and length fields)
|
||||
*
|
||||
* Name is defined in RFC 5280.
|
||||
* </pre>
|
||||
*
|
||||
* @see ResponderId.Type
|
||||
* @since 9
|
||||
*/
|
||||
public final class ResponderId {
|
||||
|
||||
/**
|
||||
* A {@code ResponderId} enumeration describing the accepted forms for a
|
||||
* {@code ResponderId}.
|
||||
*
|
||||
* @see ResponderId
|
||||
* @since 9
|
||||
*/
|
||||
public static enum Type {
|
||||
/**
|
||||
* A BY_NAME {@code ResponderId} will be built from a subject name,
|
||||
* either as an {@code X500Principal} or a DER-encoded byte array.
|
||||
*/
|
||||
BY_NAME(1, "byName"),
|
||||
|
||||
/**
|
||||
* A BY_KEY {@code ResponderId} will be built from a public key
|
||||
* identifier, either derived from a {@code PublicKey} or directly
|
||||
* from a DER-encoded byte array containing the key identifier.
|
||||
*/
|
||||
BY_KEY(2, "byKey");
|
||||
|
||||
private final int tagNumber;
|
||||
private final String ridTypeName;
|
||||
|
||||
private Type(int value, String name) {
|
||||
this.tagNumber = value;
|
||||
this.ridTypeName = name;
|
||||
}
|
||||
|
||||
public int value() {
|
||||
return tagNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ridTypeName;
|
||||
}
|
||||
}
|
||||
|
||||
private Type type;
|
||||
private X500Principal responderName;
|
||||
private KeyIdentifier responderKeyId;
|
||||
private byte[] encodedRid;
|
||||
|
||||
/**
|
||||
* Constructs a {@code ResponderId} object using an {@code X500Principal}.
|
||||
* When encoded in DER this object will use the BY_NAME option.
|
||||
*
|
||||
* @param subjectName the subject name of the certificate used
|
||||
* to sign OCSP responses.
|
||||
*
|
||||
* @throws IOException if the internal DER-encoding of the
|
||||
* {@code X500Principal} fails.
|
||||
*/
|
||||
public ResponderId(X500Principal subjectName) throws IOException {
|
||||
responderName = subjectName;
|
||||
responderKeyId = null;
|
||||
encodedRid = principalToBytes();
|
||||
type = Type.BY_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code ResponderId} object using a {@code PublicKey}.
|
||||
* When encoded in DER this object will use the byKey option, a
|
||||
* SHA-1 hash of the responder's public key.
|
||||
*
|
||||
* @param pubKey the the OCSP responder's public key
|
||||
*
|
||||
* @throws IOException if the internal DER-encoding of the
|
||||
* {@code KeyIdentifier} fails.
|
||||
*/
|
||||
public ResponderId(PublicKey pubKey) throws IOException {
|
||||
responderKeyId = new KeyIdentifier(pubKey);
|
||||
responderName = null;
|
||||
encodedRid = keyIdToBytes();
|
||||
type = Type.BY_KEY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code ResponderId} object from its DER-encoding.
|
||||
*
|
||||
* @param encodedData the DER-encoded bytes
|
||||
*
|
||||
* @throws IOException if the encodedData is not properly DER encoded
|
||||
*/
|
||||
public ResponderId(byte[] encodedData) throws IOException {
|
||||
DerValue outer = new DerValue(encodedData);
|
||||
|
||||
if (outer.isContextSpecific((byte)Type.BY_NAME.value())
|
||||
&& outer.isConstructed()) {
|
||||
// Use the X500Principal constructor as a way to sanity
|
||||
// check the incoming data.
|
||||
responderName = new X500Principal(outer.getDataBytes());
|
||||
encodedRid = principalToBytes();
|
||||
type = Type.BY_NAME;
|
||||
} else if (outer.isContextSpecific((byte)Type.BY_KEY.value())
|
||||
&& outer.isConstructed()) {
|
||||
// Use the KeyIdentifier constructor as a way to sanity
|
||||
// check the incoming data.
|
||||
responderKeyId =
|
||||
new KeyIdentifier(new DerValue(outer.getDataBytes()));
|
||||
encodedRid = keyIdToBytes();
|
||||
type = Type.BY_KEY;
|
||||
} else {
|
||||
throw new IOException("Invalid ResponderId content");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a {@code ResponderId} in DER form
|
||||
*
|
||||
* @return a byte array containing the DER-encoded representation for this
|
||||
* {@code ResponderId}
|
||||
*/
|
||||
public byte[] getEncoded() {
|
||||
return encodedRid.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of {@ResponderId}
|
||||
*
|
||||
* @return a number corresponding to the context-specific tag number
|
||||
* used in the DER-encoding for a {@code ResponderId}
|
||||
*/
|
||||
public ResponderId.Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the length of the encoded {@code ResponderId} (including the tag and
|
||||
* length of the explicit tagging from the outer ASN.1 CHOICE).
|
||||
*
|
||||
* @return the length of the encoded {@code ResponderId}
|
||||
*/
|
||||
public int length() {
|
||||
return encodedRid.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the underlying {@code X500Principal} from a {@code ResponderId}
|
||||
*
|
||||
* @return the {@code X500Principal} for this {@code ResponderId} if it
|
||||
* is a BY_NAME variant. If the {@code ResponderId} is a BY_KEY
|
||||
* variant, this routine will return {@code null}.
|
||||
*/
|
||||
public X500Principal getResponderName() {
|
||||
return responderName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the underlying key identifier from a {@code ResponderId}
|
||||
*
|
||||
* @return the {@code KeyIdentifier} for this {@code ResponderId} if it
|
||||
* is a BY_KEY variant. If the {@code ResponderId} is a BY_NAME
|
||||
* variant, this routine will return {@code null}.
|
||||
*/
|
||||
public KeyIdentifier getKeyIdentifier() {
|
||||
return responderKeyId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the specified object with this {@code ResponderId} for equality.
|
||||
* A ResponderId will only be considered equivalent if both the type and
|
||||
* data value are equal. Two ResponderIds initialized by name and
|
||||
* key ID, respectively, will not be equal even if the
|
||||
* ResponderId objects are created from the same source certificate.
|
||||
*
|
||||
* @param obj the object to be compared against
|
||||
*
|
||||
* @return true if the specified object is equal to this {@code Responderid}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj instanceof ResponderId) {
|
||||
ResponderId respObj = (ResponderId)obj;
|
||||
return Arrays.equals(encodedRid, respObj.getEncoded());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash code value for this {@code ResponderId}
|
||||
*
|
||||
* @return the hash code value for this {@code ResponderId}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(encodedRid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a String representation of this {@code ResponderId}
|
||||
*
|
||||
* @return a String representation of this {@code ResponderId}
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
switch (type) {
|
||||
case BY_NAME:
|
||||
sb.append(type).append(": ").append(responderName);
|
||||
break;
|
||||
case BY_KEY:
|
||||
sb.append(type).append(": ");
|
||||
for (byte keyIdByte : responderKeyId.getIdentifier()) {
|
||||
sb.append(String.format("%02X", keyIdByte));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sb.append("Unknown ResponderId Type: ").append(type);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the responderName data member into its DER-encoded form
|
||||
*
|
||||
* @return the DER encoding for a responder ID byName option, including
|
||||
* explicit context-specific tagging.
|
||||
*
|
||||
* @throws IOException if any encoding error occurs
|
||||
*/
|
||||
private byte[] principalToBytes() throws IOException {
|
||||
DerValue dv = new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte)Type.BY_NAME.value()),
|
||||
responderName.getEncoded());
|
||||
return dv.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the responderKeyId data member into its DER-encoded form
|
||||
*
|
||||
* @return the DER encoding for a responder ID byKey option, including
|
||||
* explicit context-specific tagging.
|
||||
*
|
||||
* @throws IOException if any encoding error occurs
|
||||
*/
|
||||
private byte[] keyIdToBytes() throws IOException {
|
||||
// Place the KeyIdentifier bytes into an OCTET STRING
|
||||
DerValue inner = new DerValue(DerValue.tag_OctetString,
|
||||
responderKeyId.getIdentifier());
|
||||
|
||||
// Mark the OCTET STRING-wrapped KeyIdentifier bytes
|
||||
// as EXPLICIT CONTEXT 2
|
||||
DerValue outer = new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte)Type.BY_KEY.value()), inner.toByteArray());
|
||||
|
||||
return outer.toByteArray();
|
||||
}
|
||||
|
||||
}
|
||||
1177
jdkSrc/jdk8/sun/security/provider/certpath/RevocationChecker.java
Normal file
1177
jdkSrc/jdk8/sun/security/provider/certpath/RevocationChecker.java
Normal file
File diff suppressed because it is too large
Load Diff
65
jdkSrc/jdk8/sun/security/provider/certpath/State.java
Normal file
65
jdkSrc/jdk8/sun/security/provider/certpath/State.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.cert.CertPathValidatorException;
|
||||
|
||||
/**
|
||||
* A specification of a PKIX validation state
|
||||
* which is initialized by each build and updated each time a
|
||||
* certificate is added to the current path.
|
||||
*
|
||||
* @since 1.4
|
||||
* @author Sean Mullan
|
||||
* @author Yassir Elley
|
||||
*/
|
||||
|
||||
interface State extends Cloneable {
|
||||
|
||||
/**
|
||||
* Update the state with the next certificate added to the path.
|
||||
*
|
||||
* @param cert the certificate which is used to update the state
|
||||
*/
|
||||
public void updateState(X509Certificate cert)
|
||||
throws CertificateException, IOException, CertPathValidatorException;
|
||||
|
||||
/**
|
||||
* Creates and returns a copy of this object
|
||||
*/
|
||||
public Object clone();
|
||||
|
||||
/**
|
||||
* Returns a boolean flag indicating if the state is initial
|
||||
* (just starting)
|
||||
*
|
||||
* @return boolean flag indicating if the state is initial (just starting)
|
||||
*/
|
||||
public boolean isInitial();
|
||||
}
|
||||
@@ -0,0 +1,654 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.*;
|
||||
import java.security.cert.CertPathValidatorException.BasicReason;
|
||||
import java.security.cert.PKIXReason;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Set;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
import sun.security.provider.certpath.PKIX.BuilderParams;
|
||||
import static sun.security.x509.PKIXExtensions.*;
|
||||
import sun.security.x509.SubjectAlternativeNameExtension;
|
||||
import sun.security.x509.X509CertImpl;
|
||||
import sun.security.util.Debug;
|
||||
|
||||
/**
|
||||
* This class builds certification paths in the forward direction.
|
||||
*
|
||||
* <p> If successful, it returns a certification path which has successfully
|
||||
* satisfied all the constraints and requirements specified in the
|
||||
* PKIXBuilderParameters object and has been validated according to the PKIX
|
||||
* path validation algorithm defined in RFC 5280.
|
||||
*
|
||||
* <p> This implementation uses a depth-first search approach to finding
|
||||
* certification paths. If it comes to a point in which it cannot find
|
||||
* any more certificates leading to the target OR the path length is too long
|
||||
* it backtracks to previous paths until the target has been found or
|
||||
* all possible paths have been exhausted.
|
||||
*
|
||||
* <p> This implementation is not thread-safe.
|
||||
*
|
||||
* @since 1.4
|
||||
* @author Sean Mullan
|
||||
* @author Yassir Elley
|
||||
*/
|
||||
public final class SunCertPathBuilder extends CertPathBuilderSpi {
|
||||
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
|
||||
/*
|
||||
* private objects shared by methods
|
||||
*/
|
||||
private BuilderParams buildParams;
|
||||
private CertificateFactory cf;
|
||||
private boolean pathCompleted = false;
|
||||
private PolicyNode policyTreeResult;
|
||||
private TrustAnchor trustAnchor;
|
||||
private PublicKey finalPublicKey;
|
||||
|
||||
/**
|
||||
* Create an instance of <code>SunCertPathBuilder</code>.
|
||||
*
|
||||
* @throws CertPathBuilderException if an error occurs
|
||||
*/
|
||||
public SunCertPathBuilder() throws CertPathBuilderException {
|
||||
try {
|
||||
cf = CertificateFactory.getInstance("X.509");
|
||||
} catch (CertificateException e) {
|
||||
throw new CertPathBuilderException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CertPathChecker engineGetRevocationChecker() {
|
||||
return new RevocationChecker();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to build a certification path using the Sun build
|
||||
* algorithm from a trusted anchor(s) to a target subject, which must both
|
||||
* be specified in the input parameter set. This method will
|
||||
* attempt to build in the forward direction: from the target to the CA.
|
||||
*
|
||||
* <p>The certification path that is constructed is validated
|
||||
* according to the PKIX specification.
|
||||
*
|
||||
* @param params the parameter set for building a path. Must be an instance
|
||||
* of <code>PKIXBuilderParameters</code>.
|
||||
* @return a certification path builder result.
|
||||
* @exception CertPathBuilderException Exception thrown if builder is
|
||||
* unable to build a complete certification path from the trusted anchor(s)
|
||||
* to the target subject.
|
||||
* @throws InvalidAlgorithmParameterException if the given parameters are
|
||||
* inappropriate for this certification path builder.
|
||||
*/
|
||||
@Override
|
||||
public CertPathBuilderResult engineBuild(CertPathParameters params)
|
||||
throws CertPathBuilderException, InvalidAlgorithmParameterException {
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("SunCertPathBuilder.engineBuild(" + params + ")");
|
||||
}
|
||||
|
||||
buildParams = PKIX.checkBuilderParams(params);
|
||||
return build();
|
||||
}
|
||||
|
||||
private PKIXCertPathBuilderResult build() throws CertPathBuilderException {
|
||||
List<List<Vertex>> adjList = new ArrayList<>();
|
||||
PKIXCertPathBuilderResult result = buildCertPath(false, adjList);
|
||||
if (result == null) {
|
||||
if (buildParams.certStores().size() > 1 || Builder.USE_AIA) {
|
||||
if (debug != null) {
|
||||
debug.println("SunCertPathBuilder.engineBuild: 2nd pass; " +
|
||||
"try building again searching all certstores");
|
||||
}
|
||||
// try again
|
||||
adjList.clear();
|
||||
result = buildCertPath(true, adjList);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
throw new SunCertPathBuilderException("unable to find valid "
|
||||
+ "certification path to requested target",
|
||||
new AdjacencyList(adjList));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private PKIXCertPathBuilderResult buildCertPath(boolean searchAllCertStores,
|
||||
List<List<Vertex>> adjList)
|
||||
throws CertPathBuilderException
|
||||
{
|
||||
// Init shared variables and build certification path
|
||||
pathCompleted = false;
|
||||
trustAnchor = null;
|
||||
finalPublicKey = null;
|
||||
policyTreeResult = null;
|
||||
LinkedList<X509Certificate> certPathList = new LinkedList<>();
|
||||
try {
|
||||
buildForward(adjList, certPathList, searchAllCertStores);
|
||||
} catch (GeneralSecurityException | IOException e) {
|
||||
if (debug != null) {
|
||||
debug.println("SunCertPathBuilder.engineBuild() exception in "
|
||||
+ "build");
|
||||
e.printStackTrace();
|
||||
}
|
||||
throw new SunCertPathBuilderException("unable to find valid "
|
||||
+ "certification path to requested target", e,
|
||||
new AdjacencyList(adjList));
|
||||
}
|
||||
|
||||
// construct SunCertPathBuilderResult
|
||||
try {
|
||||
if (pathCompleted) {
|
||||
if (debug != null)
|
||||
debug.println("SunCertPathBuilder.engineBuild() "
|
||||
+ "pathCompleted");
|
||||
|
||||
// we must return a certpath which has the target
|
||||
// as the first cert in the certpath - i.e. reverse
|
||||
// the certPathList
|
||||
Collections.reverse(certPathList);
|
||||
|
||||
return new SunCertPathBuilderResult(
|
||||
cf.generateCertPath(certPathList), trustAnchor,
|
||||
policyTreeResult, finalPublicKey,
|
||||
new AdjacencyList(adjList));
|
||||
}
|
||||
} catch (CertificateException e) {
|
||||
if (debug != null) {
|
||||
debug.println("SunCertPathBuilder.engineBuild() exception "
|
||||
+ "in wrap-up");
|
||||
e.printStackTrace();
|
||||
}
|
||||
throw new SunCertPathBuilderException("unable to find valid "
|
||||
+ "certification path to requested target", e,
|
||||
new AdjacencyList(adjList));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Private build forward method.
|
||||
*/
|
||||
private void buildForward(List<List<Vertex>> adjacencyList,
|
||||
LinkedList<X509Certificate> certPathList,
|
||||
boolean searchAllCertStores)
|
||||
throws GeneralSecurityException, IOException
|
||||
{
|
||||
if (debug != null) {
|
||||
debug.println("SunCertPathBuilder.buildForward()...");
|
||||
}
|
||||
|
||||
/* Initialize current state */
|
||||
ForwardState currentState = new ForwardState();
|
||||
currentState.initState(buildParams.certPathCheckers());
|
||||
|
||||
/* Initialize adjacency list */
|
||||
adjacencyList.clear();
|
||||
adjacencyList.add(new LinkedList<Vertex>());
|
||||
|
||||
currentState.untrustedChecker = new UntrustedChecker();
|
||||
|
||||
depthFirstSearchForward(buildParams.targetSubject(), currentState,
|
||||
new ForwardBuilder(buildParams,
|
||||
searchAllCertStores),
|
||||
adjacencyList, certPathList);
|
||||
}
|
||||
|
||||
/*
|
||||
* This method performs a depth first search for a certification
|
||||
* path while building forward which meets the requirements set in
|
||||
* the parameters object.
|
||||
* It uses an adjacency list to store all certificates which were
|
||||
* tried (i.e. at one time added to the path - they may not end up in
|
||||
* the final path if backtracking occurs). This information can
|
||||
* be used later to debug or demo the build.
|
||||
*
|
||||
* See "Data Structure and Algorithms, by Aho, Hopcroft, and Ullman"
|
||||
* for an explanation of the DFS algorithm.
|
||||
*
|
||||
* @param dN the distinguished name being currently searched for certs
|
||||
* @param currentState the current PKIX validation state
|
||||
*/
|
||||
private void depthFirstSearchForward(X500Principal dN,
|
||||
ForwardState currentState,
|
||||
ForwardBuilder builder,
|
||||
List<List<Vertex>> adjList,
|
||||
LinkedList<X509Certificate> cpList)
|
||||
throws GeneralSecurityException, IOException
|
||||
{
|
||||
if (debug != null) {
|
||||
debug.println("SunCertPathBuilder.depthFirstSearchForward(" + dN
|
||||
+ ", " + currentState.toString() + ")");
|
||||
}
|
||||
|
||||
/*
|
||||
* Find all the certificates issued to dN which
|
||||
* satisfy the PKIX certification path constraints.
|
||||
*/
|
||||
Collection<X509Certificate> certs =
|
||||
builder.getMatchingCerts(currentState, buildParams.certStores());
|
||||
List<Vertex> vertices = addVertices(certs, adjList, cpList);
|
||||
if (debug != null) {
|
||||
debug.println("SunCertPathBuilder.depthFirstSearchForward(): "
|
||||
+ "certs.size=" + vertices.size());
|
||||
}
|
||||
|
||||
/*
|
||||
* For each cert in the collection, verify anything
|
||||
* that hasn't been checked yet (signature, revocation, etc)
|
||||
* and check for certs with repeated public key and subject.
|
||||
* Call depthFirstSearchForward() recursively for each good cert.
|
||||
*/
|
||||
|
||||
vertices:
|
||||
for (Vertex vertex : vertices) {
|
||||
/**
|
||||
* Restore state to currentState each time through the loop.
|
||||
* This is important because some of the user-defined
|
||||
* checkers modify the state, which MUST be restored if
|
||||
* the cert eventually fails to lead to the target and
|
||||
* the next matching cert is tried.
|
||||
*/
|
||||
ForwardState nextState = (ForwardState) currentState.clone();
|
||||
X509Certificate cert = vertex.getCertificate();
|
||||
|
||||
try {
|
||||
builder.verifyCert(cert, nextState, cpList);
|
||||
} catch (GeneralSecurityException gse) {
|
||||
if (debug != null) {
|
||||
debug.println("SunCertPathBuilder.depthFirstSearchForward()"
|
||||
+ ": validation failed: " + gse);
|
||||
gse.printStackTrace();
|
||||
}
|
||||
vertex.setThrowable(gse);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Certificate is good.
|
||||
* If cert completes the path,
|
||||
* process userCheckers that don't support forward checking
|
||||
* and process policies over whole path
|
||||
* and backtrack appropriately if there is a failure
|
||||
* else if cert does not complete the path,
|
||||
* add it to the path
|
||||
*/
|
||||
if (builder.isPathCompleted(cert)) {
|
||||
|
||||
if (debug != null)
|
||||
debug.println("SunCertPathBuilder.depthFirstSearchForward()"
|
||||
+ ": commencing final verification");
|
||||
|
||||
List<X509Certificate> appendedCerts = new ArrayList<>(cpList);
|
||||
|
||||
/*
|
||||
* if the trust anchor selected is specified as a trusted
|
||||
* public key rather than a trusted cert, then verify this
|
||||
* cert (which is signed by the trusted public key), but
|
||||
* don't add it yet to the cpList
|
||||
*/
|
||||
PublicKey rootKey = cert.getPublicKey();
|
||||
if (builder.trustAnchor.getTrustedCert() == null) {
|
||||
appendedCerts.add(0, cert);
|
||||
rootKey = builder.trustAnchor.getCAPublicKey();
|
||||
if (debug != null)
|
||||
debug.println(
|
||||
"SunCertPathBuilder.depthFirstSearchForward " +
|
||||
"using buildParams public key: " +
|
||||
rootKey.toString());
|
||||
}
|
||||
TrustAnchor anchor = new TrustAnchor
|
||||
(cert.getSubjectX500Principal(), rootKey, null);
|
||||
|
||||
// add the basic checker
|
||||
List<PKIXCertPathChecker> checkers = new ArrayList<>();
|
||||
BasicChecker basicChecker = new BasicChecker(anchor,
|
||||
buildParams.date(),
|
||||
buildParams.sigProvider(),
|
||||
true);
|
||||
checkers.add(basicChecker);
|
||||
Set<String> initExpPolSet =
|
||||
Collections.singleton(PolicyChecker.ANY_POLICY);
|
||||
|
||||
PolicyNodeImpl rootNode = new PolicyNodeImpl(null,
|
||||
PolicyChecker.ANY_POLICY, null, false, initExpPolSet, false);
|
||||
|
||||
PolicyChecker policyChecker
|
||||
= new PolicyChecker(buildParams.initialPolicies(),
|
||||
appendedCerts.size(),
|
||||
buildParams.explicitPolicyRequired(),
|
||||
buildParams.policyMappingInhibited(),
|
||||
buildParams.anyPolicyInhibited(),
|
||||
buildParams.policyQualifiersRejected(),
|
||||
rootNode);
|
||||
checkers.add(policyChecker);
|
||||
|
||||
// add the constraints checker
|
||||
checkers.add(new ConstraintsChecker(appendedCerts.size()));
|
||||
|
||||
// add the algorithm checker
|
||||
checkers.add(new AlgorithmChecker(builder.trustAnchor,
|
||||
buildParams.timestamp(), buildParams.variant()));
|
||||
|
||||
|
||||
buildParams.setCertPath(cf.generateCertPath(appendedCerts));
|
||||
|
||||
boolean revCheckerAdded = false;
|
||||
List<PKIXCertPathChecker> ckrs = buildParams.certPathCheckers();
|
||||
for (PKIXCertPathChecker ckr : ckrs) {
|
||||
if (ckr instanceof PKIXRevocationChecker) {
|
||||
if (revCheckerAdded) {
|
||||
throw new CertPathValidatorException(
|
||||
"Only one PKIXRevocationChecker can be specified");
|
||||
}
|
||||
revCheckerAdded = true;
|
||||
// if it's our own, initialize it
|
||||
if (ckr instanceof RevocationChecker) {
|
||||
((RevocationChecker)ckr).init(builder.trustAnchor,
|
||||
buildParams);
|
||||
}
|
||||
}
|
||||
}
|
||||
// only add a RevocationChecker if revocation is enabled and
|
||||
// a PKIXRevocationChecker has not already been added
|
||||
if (buildParams.revocationEnabled() && !revCheckerAdded) {
|
||||
checkers.add(new RevocationChecker(builder.trustAnchor,
|
||||
buildParams));
|
||||
}
|
||||
|
||||
checkers.addAll(ckrs);
|
||||
|
||||
// Why we don't need BasicChecker and RevocationChecker
|
||||
// if nextState.keyParamsNeeded() is false?
|
||||
|
||||
for (int i = 0; i < appendedCerts.size(); i++) {
|
||||
X509Certificate currCert = appendedCerts.get(i);
|
||||
if (debug != null)
|
||||
debug.println("current subject = "
|
||||
+ currCert.getSubjectX500Principal());
|
||||
Set<String> unresCritExts =
|
||||
currCert.getCriticalExtensionOIDs();
|
||||
if (unresCritExts == null) {
|
||||
unresCritExts = Collections.<String>emptySet();
|
||||
}
|
||||
|
||||
for (PKIXCertPathChecker currChecker : checkers) {
|
||||
if (!currChecker.isForwardCheckingSupported()) {
|
||||
if (i == 0) {
|
||||
currChecker.init(false);
|
||||
|
||||
// The user specified
|
||||
// AlgorithmChecker may not be
|
||||
// able to set the trust anchor until now.
|
||||
if (currChecker instanceof AlgorithmChecker) {
|
||||
((AlgorithmChecker)currChecker).
|
||||
trySetTrustAnchor(builder.trustAnchor);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
currChecker.check(currCert, unresCritExts);
|
||||
} catch (CertPathValidatorException cpve) {
|
||||
if (debug != null)
|
||||
debug.println
|
||||
("SunCertPathBuilder.depthFirstSearchForward(): " +
|
||||
"final verification failed: " + cpve);
|
||||
// If the target cert itself is revoked, we
|
||||
// cannot trust it. We can bail out here.
|
||||
if (buildParams.targetCertConstraints().match(currCert)
|
||||
&& cpve.getReason() == BasicReason.REVOKED) {
|
||||
throw cpve;
|
||||
}
|
||||
vertex.setThrowable(cpve);
|
||||
continue vertices;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove extensions from user checkers that support
|
||||
* forward checking. After this step, we will have
|
||||
* removed all extensions that all user checkers
|
||||
* are capable of processing.
|
||||
*/
|
||||
for (PKIXCertPathChecker checker :
|
||||
buildParams.certPathCheckers())
|
||||
{
|
||||
if (checker.isForwardCheckingSupported()) {
|
||||
Set<String> suppExts =
|
||||
checker.getSupportedExtensions();
|
||||
if (suppExts != null) {
|
||||
unresCritExts.removeAll(suppExts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!unresCritExts.isEmpty()) {
|
||||
unresCritExts.remove(BasicConstraints_Id.toString());
|
||||
unresCritExts.remove(NameConstraints_Id.toString());
|
||||
unresCritExts.remove(CertificatePolicies_Id.toString());
|
||||
unresCritExts.remove(PolicyMappings_Id.toString());
|
||||
unresCritExts.remove(PolicyConstraints_Id.toString());
|
||||
unresCritExts.remove(InhibitAnyPolicy_Id.toString());
|
||||
unresCritExts.remove(
|
||||
SubjectAlternativeName_Id.toString());
|
||||
unresCritExts.remove(KeyUsage_Id.toString());
|
||||
unresCritExts.remove(ExtendedKeyUsage_Id.toString());
|
||||
|
||||
if (!unresCritExts.isEmpty()) {
|
||||
throw new CertPathValidatorException
|
||||
("unrecognized critical extension(s)", null,
|
||||
null, -1, PKIXReason.UNRECOGNIZED_CRIT_EXT);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (debug != null)
|
||||
debug.println("SunCertPathBuilder.depthFirstSearchForward()"
|
||||
+ ": final verification succeeded - path completed!");
|
||||
pathCompleted = true;
|
||||
|
||||
/*
|
||||
* if the user specified a trusted public key rather than
|
||||
* trusted certs, then add this cert (which is signed by
|
||||
* the trusted public key) to the cpList
|
||||
*/
|
||||
if (builder.trustAnchor.getTrustedCert() == null)
|
||||
builder.addCertToPath(cert, cpList);
|
||||
// Save the trust anchor
|
||||
this.trustAnchor = builder.trustAnchor;
|
||||
|
||||
/*
|
||||
* Extract and save the final target public key
|
||||
*/
|
||||
if (basicChecker != null) {
|
||||
finalPublicKey = basicChecker.getPublicKey();
|
||||
} else {
|
||||
Certificate finalCert;
|
||||
if (cpList.isEmpty()) {
|
||||
finalCert = builder.trustAnchor.getTrustedCert();
|
||||
} else {
|
||||
finalCert = cpList.getLast();
|
||||
}
|
||||
finalPublicKey = finalCert.getPublicKey();
|
||||
}
|
||||
|
||||
policyTreeResult = policyChecker.getPolicyTree();
|
||||
return;
|
||||
} else {
|
||||
// If successive certs are self-issued, don't continue search
|
||||
// on this branch.
|
||||
if (currentState.selfIssued && X509CertImpl.isSelfIssued(cert)) {
|
||||
if (debug != null) {
|
||||
debug.println("Successive certs are self-issued");
|
||||
}
|
||||
return;
|
||||
}
|
||||
builder.addCertToPath(cert, cpList);
|
||||
}
|
||||
|
||||
/* Update the PKIX state */
|
||||
nextState.updateState(cert);
|
||||
|
||||
/*
|
||||
* Append an entry for cert in adjacency list and
|
||||
* set index for current vertex.
|
||||
*/
|
||||
adjList.add(new LinkedList<Vertex>());
|
||||
vertex.setIndex(adjList.size() - 1);
|
||||
|
||||
/* recursively search for matching certs at next dN */
|
||||
depthFirstSearchForward(cert.getIssuerX500Principal(), nextState,
|
||||
builder, adjList, cpList);
|
||||
|
||||
/*
|
||||
* If path has been completed, return ASAP!
|
||||
*/
|
||||
if (pathCompleted) {
|
||||
return;
|
||||
} else {
|
||||
/*
|
||||
* If we get here, it means we have searched all possible
|
||||
* certs issued by the dN w/o finding any matching certs.
|
||||
* This means we have to backtrack to the previous cert in
|
||||
* the path and try some other paths.
|
||||
*/
|
||||
if (debug != null)
|
||||
debug.println("SunCertPathBuilder.depthFirstSearchForward()"
|
||||
+ ": backtracking");
|
||||
builder.removeFinalCertFromPath(cpList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds a collection of matching certificates to the
|
||||
* adjacency list.
|
||||
*/
|
||||
private static List<Vertex> addVertices(Collection<X509Certificate> certs,
|
||||
List<List<Vertex>> adjList,
|
||||
List<X509Certificate> cpList)
|
||||
{
|
||||
List<Vertex> l = adjList.get(adjList.size() - 1);
|
||||
|
||||
for (X509Certificate cert : certs) {
|
||||
boolean repeated = false;
|
||||
for (X509Certificate cpListCert : cpList) {
|
||||
/*
|
||||
* Ignore if we encounter the same certificate or a
|
||||
* certificate with the same public key, subject DN, and
|
||||
* subjectAltNames as a cert that is already in path.
|
||||
*/
|
||||
if (repeated(cpListCert, cert)) {
|
||||
if (debug != null) {
|
||||
debug.println("cert with repeated subject, " +
|
||||
"public key, and subjectAltNames detected");
|
||||
}
|
||||
repeated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!repeated) {
|
||||
l.add(new Vertex(cert));
|
||||
}
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if two certificates are equal or have the same subject,
|
||||
* public key, and subject alternative names.
|
||||
*/
|
||||
private static boolean repeated(
|
||||
X509Certificate currCert, X509Certificate nextCert) {
|
||||
if (currCert.equals(nextCert)) {
|
||||
return true;
|
||||
}
|
||||
return (currCert.getSubjectX500Principal().equals(
|
||||
nextCert.getSubjectX500Principal()) &&
|
||||
currCert.getPublicKey().equals(nextCert.getPublicKey()) &&
|
||||
altNamesEqual(currCert, nextCert));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if two certificates have the same subject alternative names.
|
||||
*/
|
||||
private static boolean altNamesEqual(
|
||||
X509Certificate currCert, X509Certificate nextCert) {
|
||||
X509CertImpl curr, next;
|
||||
try {
|
||||
curr = X509CertImpl.toImpl(currCert);
|
||||
next = X509CertImpl.toImpl(nextCert);
|
||||
} catch (CertificateException ce) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SubjectAlternativeNameExtension currAltNameExt =
|
||||
curr.getSubjectAlternativeNameExtension();
|
||||
SubjectAlternativeNameExtension nextAltNameExt =
|
||||
next.getSubjectAlternativeNameExtension();
|
||||
if (currAltNameExt != null) {
|
||||
if (nextAltNameExt == null) {
|
||||
return false;
|
||||
}
|
||||
return Arrays.equals(currAltNameExt.getExtensionValue(),
|
||||
nextAltNameExt.getExtensionValue());
|
||||
} else {
|
||||
return (nextAltNameExt == null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if trust anchor certificate matches specified
|
||||
* certificate constraints.
|
||||
*/
|
||||
private static boolean anchorIsTarget(TrustAnchor anchor,
|
||||
CertSelector sel)
|
||||
{
|
||||
X509Certificate anchorCert = anchor.getTrustedCert();
|
||||
if (anchorCert != null) {
|
||||
return sel.match(anchorCert);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.util.List;
|
||||
import java.security.cert.CertPathBuilderException;
|
||||
|
||||
/**
|
||||
* This is a subclass of the generic <code>CertPathBuilderException</code>.
|
||||
* It contains an adjacency list with information regarding the unsuccessful
|
||||
* paths that the SunCertPathBuilder tried.
|
||||
*
|
||||
* @since 1.4
|
||||
* @author Sean Mullan
|
||||
* @see CertPathBuilderException
|
||||
*/
|
||||
public class SunCertPathBuilderException extends CertPathBuilderException {
|
||||
|
||||
private static final long serialVersionUID = -7814288414129264709L;
|
||||
|
||||
/**
|
||||
* @serial
|
||||
*/
|
||||
private transient AdjacencyList adjList;
|
||||
|
||||
/**
|
||||
* Constructs a <code>SunCertPathBuilderException</code> with
|
||||
* <code>null</code> as its detail message.
|
||||
*/
|
||||
public SunCertPathBuilderException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>SunCertPathBuilderException</code> with the specified
|
||||
* detail message. A detail message is a <code>String</code> that
|
||||
* describes this particular exception.
|
||||
*
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public SunCertPathBuilderException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>SunCertPathBuilderException</code> that wraps the
|
||||
* specified throwable. This allows any exception to be converted into a
|
||||
* <code>SunCertPathBuilderException</code>, while retaining information
|
||||
* about the cause, which may be useful for debugging. The detail message is
|
||||
* set to (<code>cause==null ? null : cause.toString()</code>) (which
|
||||
* typically contains the class and detail message of cause).
|
||||
*
|
||||
* @param cause the cause (which is saved for later retrieval by the
|
||||
* {@link #getCause getCause()} method). (A <code>null</code> value is
|
||||
* permitted, and indicates that the cause is nonexistent or unknown.)
|
||||
* root cause.
|
||||
*/
|
||||
public SunCertPathBuilderException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a <code>SunCertPathBuilderException</code> with the specified
|
||||
* detail message and cause.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param cause the cause
|
||||
*/
|
||||
public SunCertPathBuilderException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a <code>SunCertPathBuilderException</code> withe the specified
|
||||
* detail message and adjacency list.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param adjList the adjacency list
|
||||
*/
|
||||
SunCertPathBuilderException(String msg, AdjacencyList adjList) {
|
||||
this(msg);
|
||||
this.adjList = adjList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a <code>SunCertPathBuilderException</code> with the specified
|
||||
* detail message, cause, and adjacency list.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param cause the throwable that occurred
|
||||
* @param adjList Adjacency list
|
||||
*/
|
||||
SunCertPathBuilderException(String msg, Throwable cause,
|
||||
AdjacencyList adjList)
|
||||
{
|
||||
this(msg, cause);
|
||||
this.adjList = adjList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the adjacency list containing information about the build.
|
||||
*
|
||||
* @return the adjacency list containing information about the build
|
||||
*/
|
||||
public AdjacencyList getAdjacencyList() {
|
||||
return adjList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import sun.security.util.Debug;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.CertPath;
|
||||
import java.security.cert.PKIXCertPathBuilderResult;
|
||||
import java.security.cert.PolicyNode;
|
||||
import java.security.cert.TrustAnchor;
|
||||
|
||||
/**
|
||||
* This class represents the result of a SunCertPathBuilder build.
|
||||
* Since all paths returned by the SunCertPathProvider are PKIX validated
|
||||
* the result contains the valid policy tree and subject public key returned
|
||||
* by the algorithm. It also contains the trust anchor and debug information
|
||||
* represented in the form of an adjacency list.
|
||||
*
|
||||
* @see PKIXCertPathBuilderResult
|
||||
*
|
||||
* @since 1.4
|
||||
* @author Sean Mullan
|
||||
*/
|
||||
//@@@ Note: this class is not in public API and access to adjacency list is
|
||||
//@@@ intended for debugging/replay of Sun PKIX CertPathBuilder implementation.
|
||||
|
||||
public class SunCertPathBuilderResult extends PKIXCertPathBuilderResult {
|
||||
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
|
||||
private AdjacencyList adjList;
|
||||
|
||||
/**
|
||||
* Creates a SunCertPathBuilderResult instance.
|
||||
*
|
||||
* @param certPath the validated <code>CertPath</code>
|
||||
* @param trustAnchor a <code>TrustAnchor</code> describing the CA that
|
||||
* served as a trust anchor for the certification path
|
||||
* @param policyTree the valid policy tree, or <code>null</code>
|
||||
* if there are no valid policies
|
||||
* @param subjectPublicKey the public key of the subject
|
||||
* @param adjList an Adjacency list containing debug information
|
||||
*/
|
||||
SunCertPathBuilderResult(CertPath certPath,
|
||||
TrustAnchor trustAnchor, PolicyNode policyTree,
|
||||
PublicKey subjectPublicKey, AdjacencyList adjList)
|
||||
{
|
||||
super(certPath, trustAnchor, policyTree, subjectPublicKey);
|
||||
this.adjList = adjList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the adjacency list containing information about the build.
|
||||
*
|
||||
* @return The adjacency list containing information about the build.
|
||||
*/
|
||||
public AdjacencyList getAdjacencyList() {
|
||||
return adjList;
|
||||
}
|
||||
}
|
||||
491
jdkSrc/jdk8/sun/security/provider/certpath/URICertStore.java
Normal file
491
jdkSrc/jdk8/sun/security/provider/certpath/URICertStore.java
Normal file
@@ -0,0 +1,491 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.net.URLConnection;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.Provider;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.CertSelector;
|
||||
import java.security.cert.CertStore;
|
||||
import java.security.cert.CertStoreException;
|
||||
import java.security.cert.CertStoreParameters;
|
||||
import java.security.cert.CertStoreSpi;
|
||||
import java.security.cert.CRLException;
|
||||
import java.security.cert.CRLSelector;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.cert.X509CertSelector;
|
||||
import java.security.cert.X509CRL;
|
||||
import java.security.cert.X509CRLSelector;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import sun.security.action.GetIntegerAction;
|
||||
import sun.security.x509.AccessDescription;
|
||||
import sun.security.x509.GeneralNameInterface;
|
||||
import sun.security.x509.URIName;
|
||||
import sun.security.util.Cache;
|
||||
import sun.security.util.Debug;
|
||||
|
||||
/**
|
||||
* A <code>CertStore</code> that retrieves <code>Certificates</code> or
|
||||
* <code>CRL</code>s from a URI, for example, as specified in an X.509
|
||||
* AuthorityInformationAccess or CRLDistributionPoint extension.
|
||||
* <p>
|
||||
* For CRLs, this implementation retrieves a single DER encoded CRL per URI.
|
||||
* For Certificates, this implementation retrieves a single DER encoded CRL or
|
||||
* a collection of Certificates encoded as a PKCS#7 "certs-only" CMS message.
|
||||
* <p>
|
||||
* This <code>CertStore</code> also implements Certificate/CRL caching.
|
||||
* Currently, the cache is shared between all applications in the VM and uses a
|
||||
* hardcoded policy. The cache has a maximum size of 185 entries, which are held
|
||||
* by SoftReferences. A request will be satisfied from the cache if we last
|
||||
* checked for an update within CHECK_INTERVAL (last 30 seconds). Otherwise,
|
||||
* we open an URLConnection to download the Certificate(s)/CRL using an
|
||||
* If-Modified-Since request (HTTP) if possible. Note that both positive and
|
||||
* negative responses are cached, i.e. if we are unable to open the connection
|
||||
* or the Certificate(s)/CRL cannot be parsed, we remember this result and
|
||||
* additional calls during the CHECK_INTERVAL period do not try to open another
|
||||
* connection.
|
||||
* <p>
|
||||
* The URICertStore is not currently a standard CertStore type. We should
|
||||
* consider adding a standard "URI" CertStore type.
|
||||
*
|
||||
* @author Andreas Sterbenz
|
||||
* @author Sean Mullan
|
||||
* @since 7.0
|
||||
*/
|
||||
class URICertStore extends CertStoreSpi {
|
||||
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
|
||||
// interval between checks for update of cached Certificates/CRLs
|
||||
// (30 seconds)
|
||||
private final static int CHECK_INTERVAL = 30 * 1000;
|
||||
|
||||
// size of the cache (see Cache class for sizing recommendations)
|
||||
private final static int CACHE_SIZE = 185;
|
||||
|
||||
// X.509 certificate factory instance
|
||||
private final CertificateFactory factory;
|
||||
|
||||
// cached Collection of X509Certificates (may be empty, never null)
|
||||
private Collection<X509Certificate> certs = Collections.emptySet();
|
||||
|
||||
// cached X509CRL (may be null)
|
||||
private X509CRL crl;
|
||||
|
||||
// time we last checked for an update
|
||||
private long lastChecked;
|
||||
|
||||
// time server returned as last modified time stamp
|
||||
// or 0 if not available
|
||||
private long lastModified;
|
||||
|
||||
// the URI of this CertStore
|
||||
private URI uri;
|
||||
|
||||
// true if URI is ldap
|
||||
private boolean ldap = false;
|
||||
private CertStoreHelper ldapHelper;
|
||||
private CertStore ldapCertStore;
|
||||
private String ldapPath;
|
||||
|
||||
// Default maximum connect timeout in milliseconds (15 seconds)
|
||||
// allowed when downloading CRLs
|
||||
private static final int DEFAULT_CRL_CONNECT_TIMEOUT = 15000;
|
||||
|
||||
/**
|
||||
* Integer value indicating the connect timeout, in seconds, to be
|
||||
* used for the CRL download. A timeout of zero is interpreted as
|
||||
* an infinite timeout.
|
||||
*/
|
||||
private static final int CRL_CONNECT_TIMEOUT = initializeTimeout();
|
||||
|
||||
/**
|
||||
* Initialize the timeout length by getting the CRL timeout
|
||||
* system property. If the property has not been set, or if its
|
||||
* value is negative, set the timeout length to the default.
|
||||
*/
|
||||
private static int initializeTimeout() {
|
||||
Integer tmp = java.security.AccessController.doPrivileged(
|
||||
new GetIntegerAction("com.sun.security.crl.timeout"));
|
||||
if (tmp == null || tmp < 0) {
|
||||
return DEFAULT_CRL_CONNECT_TIMEOUT;
|
||||
}
|
||||
// Convert to milliseconds, as the system property will be
|
||||
// specified in seconds
|
||||
return tmp * 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a URICertStore.
|
||||
*
|
||||
* @param parameters specifying the URI
|
||||
*/
|
||||
URICertStore(CertStoreParameters params)
|
||||
throws InvalidAlgorithmParameterException, NoSuchAlgorithmException {
|
||||
super(params);
|
||||
if (!(params instanceof URICertStoreParameters)) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("params must be instanceof URICertStoreParameters");
|
||||
}
|
||||
this.uri = ((URICertStoreParameters) params).uri;
|
||||
// if ldap URI, use an LDAPCertStore to fetch certs and CRLs
|
||||
if (uri.getScheme().toLowerCase(Locale.ENGLISH).equals("ldap")) {
|
||||
ldap = true;
|
||||
ldapHelper = CertStoreHelper.getInstance("LDAP");
|
||||
ldapCertStore = ldapHelper.getCertStore(uri);
|
||||
ldapPath = uri.getPath();
|
||||
// strip off leading '/'
|
||||
if (ldapPath.charAt(0) == '/') {
|
||||
ldapPath = ldapPath.substring(1);
|
||||
}
|
||||
}
|
||||
try {
|
||||
factory = CertificateFactory.getInstance("X.509");
|
||||
} catch (CertificateException e) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a URI CertStore. This method consults a cache of
|
||||
* CertStores (shared per JVM) using the URI as a key.
|
||||
*/
|
||||
private static final Cache<URICertStoreParameters, CertStore>
|
||||
certStoreCache = Cache.newSoftMemoryCache(CACHE_SIZE);
|
||||
static synchronized CertStore getInstance(URICertStoreParameters params)
|
||||
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
|
||||
if (debug != null) {
|
||||
debug.println("CertStore URI:" + params.uri);
|
||||
}
|
||||
CertStore ucs = certStoreCache.get(params);
|
||||
if (ucs == null) {
|
||||
ucs = new UCS(new URICertStore(params), null, "URI", params);
|
||||
certStoreCache.put(params, ucs);
|
||||
} else {
|
||||
if (debug != null) {
|
||||
debug.println("URICertStore.getInstance: cache hit");
|
||||
}
|
||||
}
|
||||
return ucs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a CertStore from information included in the AccessDescription
|
||||
* object of a certificate's Authority Information Access Extension.
|
||||
*/
|
||||
static CertStore getInstance(AccessDescription ad) {
|
||||
if (!ad.getAccessMethod().equals((Object)
|
||||
AccessDescription.Ad_CAISSUERS_Id)) {
|
||||
return null;
|
||||
}
|
||||
GeneralNameInterface gn = ad.getAccessLocation().getName();
|
||||
if (!(gn instanceof URIName)) {
|
||||
return null;
|
||||
}
|
||||
URI uri = ((URIName) gn).getURI();
|
||||
try {
|
||||
return URICertStore.getInstance
|
||||
(new URICertStore.URICertStoreParameters(uri));
|
||||
} catch (Exception ex) {
|
||||
if (debug != null) {
|
||||
debug.println("exception creating CertStore: " + ex);
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>Collection</code> of <code>X509Certificate</code>s that
|
||||
* match the specified selector. If no <code>X509Certificate</code>s
|
||||
* match the selector, an empty <code>Collection</code> will be returned.
|
||||
*
|
||||
* @param selector a <code>CertSelector</code> used to select which
|
||||
* <code>X509Certificate</code>s should be returned. Specify
|
||||
* <code>null</code> to return all <code>X509Certificate</code>s.
|
||||
* @return a <code>Collection</code> of <code>X509Certificate</code>s that
|
||||
* match the specified selector
|
||||
* @throws CertStoreException if an exception occurs
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public synchronized Collection<X509Certificate> engineGetCertificates
|
||||
(CertSelector selector) throws CertStoreException {
|
||||
|
||||
// if ldap URI we wrap the CertSelector in an LDAPCertSelector to
|
||||
// avoid LDAP DN matching issues (see LDAPCertSelector for more info)
|
||||
if (ldap) {
|
||||
X509CertSelector xsel = (X509CertSelector) selector;
|
||||
try {
|
||||
xsel = ldapHelper.wrap(xsel, xsel.getSubject(), ldapPath);
|
||||
} catch (IOException ioe) {
|
||||
throw new CertStoreException(ioe);
|
||||
}
|
||||
// Fetch the certificates via LDAP. LDAPCertStore has its own
|
||||
// caching mechanism, see the class description for more info.
|
||||
// Safe cast since xsel is an X509 certificate selector.
|
||||
return (Collection<X509Certificate>)
|
||||
ldapCertStore.getCertificates(xsel);
|
||||
}
|
||||
|
||||
// Return the Certificates for this entry. It returns the cached value
|
||||
// if it is still current and fetches the Certificates otherwise.
|
||||
// For the caching details, see the top of this class.
|
||||
long time = System.currentTimeMillis();
|
||||
if (time - lastChecked < CHECK_INTERVAL) {
|
||||
if (debug != null) {
|
||||
debug.println("Returning certificates from cache");
|
||||
}
|
||||
return getMatchingCerts(certs, selector);
|
||||
}
|
||||
lastChecked = time;
|
||||
try {
|
||||
URLConnection connection = uri.toURL().openConnection();
|
||||
if (lastModified != 0) {
|
||||
connection.setIfModifiedSince(lastModified);
|
||||
}
|
||||
long oldLastModified = lastModified;
|
||||
try (InputStream in = connection.getInputStream()) {
|
||||
lastModified = connection.getLastModified();
|
||||
if (oldLastModified != 0) {
|
||||
if (oldLastModified == lastModified) {
|
||||
if (debug != null) {
|
||||
debug.println("Not modified, using cached copy");
|
||||
}
|
||||
return getMatchingCerts(certs, selector);
|
||||
} else if (connection instanceof HttpURLConnection) {
|
||||
// some proxy servers omit last modified
|
||||
HttpURLConnection hconn = (HttpURLConnection)connection;
|
||||
if (hconn.getResponseCode()
|
||||
== HttpURLConnection.HTTP_NOT_MODIFIED) {
|
||||
if (debug != null) {
|
||||
debug.println("Not modified, using cached copy");
|
||||
}
|
||||
return getMatchingCerts(certs, selector);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (debug != null) {
|
||||
debug.println("Downloading new certificates...");
|
||||
}
|
||||
// Safe cast since factory is an X.509 certificate factory
|
||||
certs = (Collection<X509Certificate>)
|
||||
factory.generateCertificates(in);
|
||||
}
|
||||
return getMatchingCerts(certs, selector);
|
||||
} catch (IOException | CertificateException e) {
|
||||
if (debug != null) {
|
||||
debug.println("Exception fetching certificates:");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
// exception, forget previous values
|
||||
lastModified = 0;
|
||||
certs = Collections.emptySet();
|
||||
return certs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over the specified Collection of X509Certificates and
|
||||
* returns only those that match the criteria specified in the
|
||||
* CertSelector.
|
||||
*/
|
||||
private static Collection<X509Certificate> getMatchingCerts
|
||||
(Collection<X509Certificate> certs, CertSelector selector) {
|
||||
// if selector not specified, all certs match
|
||||
if (selector == null) {
|
||||
return certs;
|
||||
}
|
||||
List<X509Certificate> matchedCerts = new ArrayList<>(certs.size());
|
||||
for (X509Certificate cert : certs) {
|
||||
if (selector.match(cert)) {
|
||||
matchedCerts.add(cert);
|
||||
}
|
||||
}
|
||||
return matchedCerts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>Collection</code> of <code>X509CRL</code>s that
|
||||
* match the specified selector. If no <code>X509CRL</code>s
|
||||
* match the selector, an empty <code>Collection</code> will be returned.
|
||||
*
|
||||
* @param selector A <code>CRLSelector</code> used to select which
|
||||
* <code>X509CRL</code>s should be returned. Specify <code>null</code>
|
||||
* to return all <code>X509CRL</code>s.
|
||||
* @return A <code>Collection</code> of <code>X509CRL</code>s that
|
||||
* match the specified selector
|
||||
* @throws CertStoreException if an exception occurs
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public synchronized Collection<X509CRL> engineGetCRLs(CRLSelector selector)
|
||||
throws CertStoreException {
|
||||
|
||||
// if ldap URI we wrap the CRLSelector in an LDAPCRLSelector to
|
||||
// avoid LDAP DN matching issues (see LDAPCRLSelector for more info)
|
||||
if (ldap) {
|
||||
X509CRLSelector xsel = (X509CRLSelector) selector;
|
||||
try {
|
||||
xsel = ldapHelper.wrap(xsel, null, ldapPath);
|
||||
} catch (IOException ioe) {
|
||||
throw new CertStoreException(ioe);
|
||||
}
|
||||
// Fetch the CRLs via LDAP. LDAPCertStore has its own
|
||||
// caching mechanism, see the class description for more info.
|
||||
// Safe cast since xsel is an X509 certificate selector.
|
||||
try {
|
||||
return (Collection<X509CRL>) ldapCertStore.getCRLs(xsel);
|
||||
} catch (CertStoreException cse) {
|
||||
throw new PKIX.CertStoreTypeException("LDAP", cse);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the CRLs for this entry. It returns the cached value
|
||||
// if it is still current and fetches the CRLs otherwise.
|
||||
// For the caching details, see the top of this class.
|
||||
long time = System.currentTimeMillis();
|
||||
if (time - lastChecked < CHECK_INTERVAL) {
|
||||
if (debug != null) {
|
||||
debug.println("Returning CRL from cache");
|
||||
}
|
||||
return getMatchingCRLs(crl, selector);
|
||||
}
|
||||
lastChecked = time;
|
||||
try {
|
||||
URLConnection connection = uri.toURL().openConnection();
|
||||
if (lastModified != 0) {
|
||||
connection.setIfModifiedSince(lastModified);
|
||||
}
|
||||
long oldLastModified = lastModified;
|
||||
connection.setConnectTimeout(CRL_CONNECT_TIMEOUT);
|
||||
try (InputStream in = connection.getInputStream()) {
|
||||
lastModified = connection.getLastModified();
|
||||
if (oldLastModified != 0) {
|
||||
if (oldLastModified == lastModified) {
|
||||
if (debug != null) {
|
||||
debug.println("Not modified, using cached copy");
|
||||
}
|
||||
return getMatchingCRLs(crl, selector);
|
||||
} else if (connection instanceof HttpURLConnection) {
|
||||
// some proxy servers omit last modified
|
||||
HttpURLConnection hconn = (HttpURLConnection)connection;
|
||||
if (hconn.getResponseCode()
|
||||
== HttpURLConnection.HTTP_NOT_MODIFIED) {
|
||||
if (debug != null) {
|
||||
debug.println("Not modified, using cached copy");
|
||||
}
|
||||
return getMatchingCRLs(crl, selector);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (debug != null) {
|
||||
debug.println("Downloading new CRL...");
|
||||
}
|
||||
crl = (X509CRL) factory.generateCRL(in);
|
||||
}
|
||||
return getMatchingCRLs(crl, selector);
|
||||
} catch (IOException | CRLException e) {
|
||||
if (debug != null) {
|
||||
debug.println("Exception fetching CRL:");
|
||||
e.printStackTrace();
|
||||
}
|
||||
// exception, forget previous values
|
||||
lastModified = 0;
|
||||
crl = null;
|
||||
throw new PKIX.CertStoreTypeException("URI",
|
||||
new CertStoreException(e));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified X509CRL matches the criteria specified in the
|
||||
* CRLSelector.
|
||||
*/
|
||||
private static Collection<X509CRL> getMatchingCRLs
|
||||
(X509CRL crl, CRLSelector selector) {
|
||||
if (selector == null || (crl != null && selector.match(crl))) {
|
||||
return Collections.singletonList(crl);
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CertStoreParameters for the URICertStore.
|
||||
*/
|
||||
static class URICertStoreParameters implements CertStoreParameters {
|
||||
private final URI uri;
|
||||
private volatile int hashCode = 0;
|
||||
URICertStoreParameters(URI uri) {
|
||||
this.uri = uri;
|
||||
}
|
||||
@Override public boolean equals(Object obj) {
|
||||
if (!(obj instanceof URICertStoreParameters)) {
|
||||
return false;
|
||||
}
|
||||
URICertStoreParameters params = (URICertStoreParameters) obj;
|
||||
return uri.equals(params.uri);
|
||||
}
|
||||
@Override public int hashCode() {
|
||||
if (hashCode == 0) {
|
||||
int result = 17;
|
||||
result = 37*result + uri.hashCode();
|
||||
hashCode = result;
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
@Override public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
/* Cannot happen */
|
||||
throw new InternalError(e.toString(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class allows the URICertStore to be accessed as a CertStore.
|
||||
*/
|
||||
private static class UCS extends CertStore {
|
||||
protected UCS(CertStoreSpi spi, Provider p, String type,
|
||||
CertStoreParameters params) {
|
||||
super(spi, p, type, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.cert.CertPathValidatorException;
|
||||
import java.security.cert.PKIXCertPathChecker;
|
||||
import java.util.Set;
|
||||
import java.util.Collection;
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.util.UntrustedCertificates;
|
||||
|
||||
/**
|
||||
* A <code>PKIXCertPathChecker</code> implementation to check whether a
|
||||
* specified certificate is distrusted.
|
||||
*
|
||||
* @see PKIXCertPathChecker
|
||||
* @see PKIXParameters
|
||||
*/
|
||||
final public class UntrustedChecker extends PKIXCertPathChecker {
|
||||
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
|
||||
/**
|
||||
* Default Constructor
|
||||
*/
|
||||
public UntrustedChecker() {
|
||||
// blank
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(boolean forward) throws CertPathValidatorException {
|
||||
// Note that this class supports both forward and reverse modes.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForwardCheckingSupported() {
|
||||
// Note that this class supports both forward and reverse modes.
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedExtensions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void check(Certificate cert,
|
||||
Collection<String> unresolvedCritExts)
|
||||
throws CertPathValidatorException {
|
||||
|
||||
X509Certificate currCert = (X509Certificate)cert;
|
||||
|
||||
if (UntrustedCertificates.isUntrusted(currCert)) {
|
||||
if (debug != null) {
|
||||
debug.println("UntrustedChecker: untrusted certificate " +
|
||||
currCert.getSubjectX500Principal());
|
||||
}
|
||||
|
||||
throw new CertPathValidatorException(
|
||||
"Untrusted certificate: " + currCert.getSubjectX500Principal());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
235
jdkSrc/jdk8/sun/security/provider/certpath/Vertex.java
Normal file
235
jdkSrc/jdk8/sun/security/provider/certpath/Vertex.java
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.x509.AuthorityKeyIdentifierExtension;
|
||||
import sun.security.x509.KeyIdentifier;
|
||||
import sun.security.x509.SubjectKeyIdentifierExtension;
|
||||
import sun.security.x509.X509CertImpl;
|
||||
|
||||
/*
|
||||
* This class represents a vertex in the adjacency list. A
|
||||
* vertex in the builder's view is just a distinguished name
|
||||
* in the directory. The Vertex contains a certificate
|
||||
* along an attempted certification path, along with a pointer
|
||||
* to a list of certificates that followed this one in various
|
||||
* attempted certification paths.
|
||||
*
|
||||
* @author Sean Mullan
|
||||
* @since 1.4
|
||||
*/
|
||||
public class Vertex {
|
||||
|
||||
private static final Debug debug = Debug.getInstance("certpath");
|
||||
private X509Certificate cert;
|
||||
private int index;
|
||||
private Throwable throwable;
|
||||
|
||||
/**
|
||||
* Constructor; creates vertex with index of -1
|
||||
* Use setIndex method to set another index.
|
||||
*
|
||||
* @param cert X509Certificate associated with vertex
|
||||
*/
|
||||
Vertex(X509Certificate cert) {
|
||||
this.cert = cert;
|
||||
this.index = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the certificate for this vertex
|
||||
*
|
||||
* @returns X509Certificate
|
||||
*/
|
||||
public X509Certificate getCertificate() {
|
||||
return cert;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the index for this vertex, where the index is the row of the
|
||||
* adjacency list that contains certificates that could follow this
|
||||
* certificate.
|
||||
*
|
||||
* @returns int index for this vertex, or -1 if no following certificates.
|
||||
*/
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the index for this vertex, where the index is the row of the
|
||||
* adjacency list that contains certificates that could follow this
|
||||
* certificate.
|
||||
*
|
||||
* @param ndx int index for vertex, or -1 if no following certificates.
|
||||
*/
|
||||
void setIndex(int ndx) {
|
||||
index = ndx;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the throwable associated with this vertex;
|
||||
* returns null if none.
|
||||
*
|
||||
* @returns Throwable
|
||||
*/
|
||||
public Throwable getThrowable() {
|
||||
return throwable;
|
||||
}
|
||||
|
||||
/**
|
||||
* set throwable associated with this vertex; default value is null.
|
||||
*
|
||||
* @param throwable Throwable associated with this vertex
|
||||
* (or null)
|
||||
*/
|
||||
void setThrowable(Throwable throwable) {
|
||||
this.throwable = throwable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return full string representation of vertex
|
||||
*
|
||||
* @returns String representation of vertex
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return certToString() + throwableToString() + indexToString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return string representation of this vertex's
|
||||
* certificate information.
|
||||
*
|
||||
* @returns String representation of certificate info
|
||||
*/
|
||||
public String certToString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
X509CertImpl x509Cert = null;
|
||||
try {
|
||||
x509Cert = X509CertImpl.toImpl(cert);
|
||||
} catch (CertificateException ce) {
|
||||
if (debug != null) {
|
||||
debug.println("Vertex.certToString() unexpected exception");
|
||||
ce.printStackTrace();
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
sb.append("Issuer: ").append
|
||||
(x509Cert.getIssuerX500Principal()).append("\n");
|
||||
sb.append("Subject: ").append
|
||||
(x509Cert.getSubjectX500Principal()).append("\n");
|
||||
sb.append("SerialNum: ").append
|
||||
(x509Cert.getSerialNumber().toString(16)).append("\n");
|
||||
sb.append("Expires: ").append
|
||||
(x509Cert.getNotAfter().toString()).append("\n");
|
||||
boolean[] iUID = x509Cert.getIssuerUniqueID();
|
||||
if (iUID != null) {
|
||||
sb.append("IssuerUID: ");
|
||||
for (boolean b : iUID) {
|
||||
sb.append(b ? 1 : 0);
|
||||
}
|
||||
sb.append("\n");
|
||||
}
|
||||
boolean[] sUID = x509Cert.getSubjectUniqueID();
|
||||
if (sUID != null) {
|
||||
sb.append("SubjectUID: ");
|
||||
for (boolean b : sUID) {
|
||||
sb.append(b ? 1 : 0);
|
||||
}
|
||||
sb.append("\n");
|
||||
}
|
||||
try {
|
||||
SubjectKeyIdentifierExtension sKeyID =
|
||||
x509Cert.getSubjectKeyIdentifierExtension();
|
||||
if (sKeyID != null) {
|
||||
KeyIdentifier keyID = sKeyID.get(
|
||||
SubjectKeyIdentifierExtension.KEY_ID);
|
||||
sb.append("SubjKeyID: ").append(keyID.toString());
|
||||
}
|
||||
AuthorityKeyIdentifierExtension aKeyID =
|
||||
x509Cert.getAuthorityKeyIdentifierExtension();
|
||||
if (aKeyID != null) {
|
||||
KeyIdentifier keyID = (KeyIdentifier)aKeyID.get(
|
||||
AuthorityKeyIdentifierExtension.KEY_ID);
|
||||
sb.append("AuthKeyID: ").append(keyID.toString());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (debug != null) {
|
||||
debug.println("Vertex.certToString() unexpected exception");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* return Vertex throwable as String compatible with
|
||||
* the way toString returns other information
|
||||
*
|
||||
* @returns String form of exception (or "none")
|
||||
*/
|
||||
public String throwableToString() {
|
||||
StringBuilder sb = new StringBuilder("Exception: ");
|
||||
if (throwable != null)
|
||||
sb.append(throwable.toString());
|
||||
else
|
||||
sb.append("null");
|
||||
sb.append("\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* return Vertex index as String compatible with
|
||||
* the way other Vertex.xToString() methods display
|
||||
* information.
|
||||
*
|
||||
* @returns String form of index as "Last cert? [Yes/No]
|
||||
*/
|
||||
public String moreToString() {
|
||||
StringBuilder sb = new StringBuilder("Last cert? ");
|
||||
sb.append((index == -1) ? "Yes" : "No");
|
||||
sb.append("\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* return Vertex index as String compatible with
|
||||
* the way other Vertex.xToString() methods displays other information.
|
||||
*
|
||||
* @returns String form of index as "Index: [numeric index]"
|
||||
*/
|
||||
public String indexToString() {
|
||||
return "Index: " + index + "\n";
|
||||
}
|
||||
}
|
||||
409
jdkSrc/jdk8/sun/security/provider/certpath/X509CertPath.java
Normal file
409
jdkSrc/jdk8/sun/security/provider/certpath/X509CertPath.java
Normal file
@@ -0,0 +1,409 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.*;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.CertPath;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.*;
|
||||
|
||||
import sun.security.pkcs.ContentInfo;
|
||||
import sun.security.pkcs.PKCS7;
|
||||
import sun.security.pkcs.SignerInfo;
|
||||
import sun.security.x509.AlgorithmId;
|
||||
import sun.security.util.DerValue;
|
||||
import sun.security.util.DerOutputStream;
|
||||
import sun.security.util.DerInputStream;
|
||||
|
||||
/**
|
||||
* A {@link java.security.cert.CertPath CertPath} (certification path)
|
||||
* consisting exclusively of
|
||||
* {@link java.security.cert.X509Certificate X509Certificate}s.
|
||||
* <p>
|
||||
* By convention, X.509 <code>CertPath</code>s are stored from target
|
||||
* to trust anchor.
|
||||
* That is, the issuer of one certificate is the subject of the following
|
||||
* one. However, unvalidated X.509 <code>CertPath</code>s may not follow
|
||||
* this convention. PKIX <code>CertPathValidator</code>s will detect any
|
||||
* departure from this convention and throw a
|
||||
* <code>CertPathValidatorException</code>.
|
||||
*
|
||||
* @author Yassir Elley
|
||||
* @since 1.4
|
||||
*/
|
||||
public class X509CertPath extends CertPath {
|
||||
|
||||
private static final long serialVersionUID = 4989800333263052980L;
|
||||
|
||||
/**
|
||||
* List of certificates in this chain
|
||||
*/
|
||||
private List<X509Certificate> certs;
|
||||
|
||||
/**
|
||||
* The names of our encodings. PkiPath is the default.
|
||||
*/
|
||||
private static final String COUNT_ENCODING = "count";
|
||||
private static final String PKCS7_ENCODING = "PKCS7";
|
||||
private static final String PKIPATH_ENCODING = "PkiPath";
|
||||
|
||||
/**
|
||||
* List of supported encodings
|
||||
*/
|
||||
private static final Collection<String> encodingList;
|
||||
|
||||
static {
|
||||
List<String> list = new ArrayList<>(2);
|
||||
list.add(PKIPATH_ENCODING);
|
||||
list.add(PKCS7_ENCODING);
|
||||
encodingList = Collections.unmodifiableCollection(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an <code>X509CertPath</code> from a <code>List</code> of
|
||||
* <code>X509Certificate</code>s.
|
||||
* <p>
|
||||
* The certificates are copied out of the supplied <code>List</code>
|
||||
* object.
|
||||
*
|
||||
* @param certs a <code>List</code> of <code>X509Certificate</code>s
|
||||
* @exception CertificateException if <code>certs</code> contains an element
|
||||
* that is not an <code>X509Certificate</code>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public X509CertPath(List<? extends Certificate> certs) throws CertificateException {
|
||||
super("X.509");
|
||||
|
||||
// Ensure that the List contains only X509Certificates
|
||||
//
|
||||
// Note; The certs parameter is not necessarily to be of Certificate
|
||||
// for some old code. For compatibility, to make sure the exception
|
||||
// is CertificateException, rather than ClassCastException, please
|
||||
// don't use
|
||||
// for (Certificate obj : certs)
|
||||
for (Object obj : certs) {
|
||||
if (obj instanceof X509Certificate == false) {
|
||||
throw new CertificateException
|
||||
("List is not all X509Certificates: "
|
||||
+ obj.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
// Assumes that the resulting List is thread-safe. This is true
|
||||
// because we ensure that it cannot be modified after construction
|
||||
// and the methods in the Sun JDK 1.4 implementation of ArrayList that
|
||||
// allow read-only access are thread-safe.
|
||||
this.certs = Collections.unmodifiableList(
|
||||
new ArrayList<X509Certificate>((List<X509Certificate>)certs));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an <code>X509CertPath</code>, reading the encoded form
|
||||
* from an <code>InputStream</code>. The data is assumed to be in
|
||||
* the default encoding.
|
||||
*
|
||||
* @param is the <code>InputStream</code> to read the data from
|
||||
* @exception CertificateException if an exception occurs while decoding
|
||||
*/
|
||||
public X509CertPath(InputStream is) throws CertificateException {
|
||||
this(is, PKIPATH_ENCODING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an <code>X509CertPath</code>, reading the encoded form
|
||||
* from an InputStream. The data is assumed to be in the specified
|
||||
* encoding.
|
||||
*
|
||||
* @param is the <code>InputStream</code> to read the data from
|
||||
* @param encoding the encoding used
|
||||
* @exception CertificateException if an exception occurs while decoding or
|
||||
* the encoding requested is not supported
|
||||
*/
|
||||
public X509CertPath(InputStream is, String encoding)
|
||||
throws CertificateException {
|
||||
super("X.509");
|
||||
|
||||
switch (encoding) {
|
||||
case PKIPATH_ENCODING:
|
||||
certs = parsePKIPATH(is);
|
||||
break;
|
||||
case PKCS7_ENCODING:
|
||||
certs = parsePKCS7(is);
|
||||
break;
|
||||
default:
|
||||
throw new CertificateException("unsupported encoding");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a PKIPATH format CertPath from an InputStream. Return an
|
||||
* unmodifiable List of the certificates.
|
||||
*
|
||||
* @param is the <code>InputStream</code> to read the data from
|
||||
* @return an unmodifiable List of the certificates
|
||||
* @exception CertificateException if an exception occurs
|
||||
*/
|
||||
private static List<X509Certificate> parsePKIPATH(InputStream is)
|
||||
throws CertificateException {
|
||||
List<X509Certificate> certList = null;
|
||||
CertificateFactory certFac = null;
|
||||
|
||||
if (is == null) {
|
||||
throw new CertificateException("input stream is null");
|
||||
}
|
||||
|
||||
try {
|
||||
DerInputStream dis = new DerInputStream(readAllBytes(is));
|
||||
DerValue[] seq = dis.getSequence(3);
|
||||
if (seq.length == 0) {
|
||||
return Collections.<X509Certificate>emptyList();
|
||||
}
|
||||
|
||||
certFac = CertificateFactory.getInstance("X.509");
|
||||
certList = new ArrayList<X509Certificate>(seq.length);
|
||||
|
||||
// append certs in reverse order (target to trust anchor)
|
||||
for (int i = seq.length-1; i >= 0; i--) {
|
||||
certList.add((X509Certificate)certFac.generateCertificate
|
||||
(new ByteArrayInputStream(seq[i].toByteArray())));
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(certList);
|
||||
|
||||
} catch (IOException ioe) {
|
||||
throw new CertificateException("IOException parsing PkiPath data: "
|
||||
+ ioe, ioe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a PKCS#7 format CertPath from an InputStream. Return an
|
||||
* unmodifiable List of the certificates.
|
||||
*
|
||||
* @param is the <code>InputStream</code> to read the data from
|
||||
* @return an unmodifiable List of the certificates
|
||||
* @exception CertificateException if an exception occurs
|
||||
*/
|
||||
private static List<X509Certificate> parsePKCS7(InputStream is)
|
||||
throws CertificateException {
|
||||
List<X509Certificate> certList;
|
||||
|
||||
if (is == null) {
|
||||
throw new CertificateException("input stream is null");
|
||||
}
|
||||
|
||||
try {
|
||||
if (is.markSupported() == false) {
|
||||
// Copy the entire input stream into an InputStream that does
|
||||
// support mark
|
||||
is = new ByteArrayInputStream(readAllBytes(is));
|
||||
}
|
||||
PKCS7 pkcs7 = new PKCS7(is);
|
||||
|
||||
X509Certificate[] certArray = pkcs7.getCertificates();
|
||||
// certs are optional in PKCS #7
|
||||
if (certArray != null) {
|
||||
certList = Arrays.asList(certArray);
|
||||
} else {
|
||||
// no certs provided
|
||||
certList = new ArrayList<X509Certificate>(0);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new CertificateException("IOException parsing PKCS7 data: " +
|
||||
ioe);
|
||||
}
|
||||
// Assumes that the resulting List is thread-safe. This is true
|
||||
// because we ensure that it cannot be modified after construction
|
||||
// and the methods in the Sun JDK 1.4 implementation of ArrayList that
|
||||
// allow read-only access are thread-safe.
|
||||
return Collections.unmodifiableList(certList);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads the entire contents of an InputStream into a byte array.
|
||||
*
|
||||
* @param is the InputStream to read from
|
||||
* @return the bytes read from the InputStream
|
||||
*/
|
||||
private static byte[] readAllBytes(InputStream is) throws IOException {
|
||||
byte[] buffer = new byte[8192];
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
|
||||
int n;
|
||||
while ((n = is.read(buffer)) != -1) {
|
||||
baos.write(buffer, 0, n);
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the encoded form of this certification path, using the
|
||||
* default encoding.
|
||||
*
|
||||
* @return the encoded bytes
|
||||
* @exception CertificateEncodingException if an encoding error occurs
|
||||
*/
|
||||
@Override
|
||||
public byte[] getEncoded() throws CertificateEncodingException {
|
||||
// @@@ Should cache the encoded form
|
||||
return encodePKIPATH();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the CertPath using PKIPATH format.
|
||||
*
|
||||
* @return a byte array containing the binary encoding of the PkiPath object
|
||||
* @exception CertificateEncodingException if an exception occurs
|
||||
*/
|
||||
private byte[] encodePKIPATH() throws CertificateEncodingException {
|
||||
|
||||
ListIterator<X509Certificate> li = certs.listIterator(certs.size());
|
||||
try {
|
||||
DerOutputStream bytes = new DerOutputStream();
|
||||
// encode certs in reverse order (trust anchor to target)
|
||||
// according to PkiPath format
|
||||
while (li.hasPrevious()) {
|
||||
X509Certificate cert = li.previous();
|
||||
// check for duplicate cert
|
||||
if (certs.lastIndexOf(cert) != certs.indexOf(cert)) {
|
||||
throw new CertificateEncodingException
|
||||
("Duplicate Certificate");
|
||||
}
|
||||
// get encoded certificates
|
||||
byte[] encoded = cert.getEncoded();
|
||||
bytes.write(encoded);
|
||||
}
|
||||
|
||||
// Wrap the data in a SEQUENCE
|
||||
DerOutputStream derout = new DerOutputStream();
|
||||
derout.write(DerValue.tag_SequenceOf, bytes);
|
||||
return derout.toByteArray();
|
||||
|
||||
} catch (IOException ioe) {
|
||||
throw new CertificateEncodingException("IOException encoding " +
|
||||
"PkiPath data: " + ioe, ioe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the CertPath using PKCS#7 format.
|
||||
*
|
||||
* @return a byte array containing the binary encoding of the PKCS#7 object
|
||||
* @exception CertificateEncodingException if an exception occurs
|
||||
*/
|
||||
private byte[] encodePKCS7() throws CertificateEncodingException {
|
||||
PKCS7 p7 = new PKCS7(new AlgorithmId[0],
|
||||
new ContentInfo(ContentInfo.DATA_OID, null),
|
||||
certs.toArray(new X509Certificate[certs.size()]),
|
||||
new SignerInfo[0]);
|
||||
DerOutputStream derout = new DerOutputStream();
|
||||
try {
|
||||
p7.encodeSignedData(derout);
|
||||
} catch (IOException ioe) {
|
||||
throw new CertificateEncodingException(ioe.getMessage());
|
||||
}
|
||||
return derout.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the encoded form of this certification path, using the
|
||||
* specified encoding.
|
||||
*
|
||||
* @param encoding the name of the encoding to use
|
||||
* @return the encoded bytes
|
||||
* @exception CertificateEncodingException if an encoding error occurs or
|
||||
* the encoding requested is not supported
|
||||
*/
|
||||
@Override
|
||||
public byte[] getEncoded(String encoding)
|
||||
throws CertificateEncodingException {
|
||||
switch (encoding) {
|
||||
case PKIPATH_ENCODING:
|
||||
return encodePKIPATH();
|
||||
case PKCS7_ENCODING:
|
||||
return encodePKCS7();
|
||||
default:
|
||||
throw new CertificateEncodingException("unsupported encoding");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the encodings supported by this certification path, with the
|
||||
* default encoding first.
|
||||
*
|
||||
* @return an <code>Iterator</code> over the names of the supported
|
||||
* encodings (as Strings)
|
||||
*/
|
||||
public static Iterator<String> getEncodingsStatic() {
|
||||
return encodingList.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iteration of the encodings supported by this certification
|
||||
* path, with the default encoding first.
|
||||
* <p>
|
||||
* Attempts to modify the returned <code>Iterator</code> via its
|
||||
* <code>remove</code> method result in an
|
||||
* <code>UnsupportedOperationException</code>.
|
||||
*
|
||||
* @return an <code>Iterator</code> over the names of the supported
|
||||
* encodings (as Strings)
|
||||
*/
|
||||
@Override
|
||||
public Iterator<String> getEncodings() {
|
||||
return getEncodingsStatic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of certificates in this certification path.
|
||||
* The <code>List</code> returned must be immutable and thread-safe.
|
||||
*
|
||||
* @return an immutable <code>List</code> of <code>X509Certificate</code>s
|
||||
* (may be empty, but not null)
|
||||
*/
|
||||
@Override
|
||||
public List<X509Certificate> getCertificates() {
|
||||
return certs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the state of this object from the stream.
|
||||
* <p>
|
||||
* Deserialization of this object is not supported.
|
||||
*
|
||||
* @param stream the {@code ObjectInputStream} from which data is read
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws ClassNotFoundException if a serialized class cannot be loaded
|
||||
*/
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException(
|
||||
"X509CertPaths are not directly deserializable");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.interfaces.DSAPublicKey;
|
||||
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
import sun.security.util.DerOutputStream;
|
||||
import sun.security.util.DerValue;
|
||||
import sun.security.util.Cache;
|
||||
import sun.security.x509.X509CertImpl;
|
||||
import sun.security.provider.X509Factory;
|
||||
|
||||
/**
|
||||
* This class represents an X.509 Certificate Pair object, which is primarily
|
||||
* used to hold a pair of cross certificates issued between Certification
|
||||
* Authorities. The ASN.1 structure is listed below. The forward certificate
|
||||
* of the CertificatePair contains a certificate issued to this CA by another
|
||||
* CA. The reverse certificate of the CertificatePair contains a certificate
|
||||
* issued by this CA to another CA. When both the forward and the reverse
|
||||
* certificates are present in the CertificatePair, the issuer name in one
|
||||
* certificate shall match the subject name in the other and vice versa, and
|
||||
* the subject public key in one certificate shall be capable of verifying the
|
||||
* digital signature on the other certificate and vice versa. If a subject
|
||||
* public key in one certificate does not contain required key algorithm
|
||||
* parameters, then the signature check involving that key is not done.<p>
|
||||
*
|
||||
* The ASN.1 syntax for this object is:
|
||||
* <pre>
|
||||
* CertificatePair ::= SEQUENCE {
|
||||
* forward [0] Certificate OPTIONAL,
|
||||
* reverse [1] Certificate OPTIONAL
|
||||
* -- at least one of the pair shall be present -- }
|
||||
* </pre><p>
|
||||
*
|
||||
* This structure uses EXPLICIT tagging. References: Annex A of
|
||||
* X.509(2000), X.509(1997).
|
||||
*
|
||||
* @author Sean Mullan
|
||||
* @since 1.4
|
||||
*/
|
||||
|
||||
public class X509CertificatePair {
|
||||
|
||||
/* ASN.1 explicit tags */
|
||||
private static final byte TAG_FORWARD = 0;
|
||||
private static final byte TAG_REVERSE = 1;
|
||||
|
||||
private X509Certificate forward;
|
||||
private X509Certificate reverse;
|
||||
private byte[] encoded;
|
||||
|
||||
private static final Cache<Object, X509CertificatePair> cache
|
||||
= Cache.newSoftMemoryCache(750);
|
||||
|
||||
/**
|
||||
* Creates an empty instance of X509CertificatePair.
|
||||
*/
|
||||
public X509CertificatePair() {}
|
||||
|
||||
/**
|
||||
* Creates an instance of X509CertificatePair. At least one of
|
||||
* the pair must be non-null.
|
||||
*
|
||||
* @param forward The forward component of the certificate pair
|
||||
* which represents a certificate issued to this CA by other CAs.
|
||||
* @param reverse The reverse component of the certificate pair
|
||||
* which represents a certificate issued by this CA to other CAs.
|
||||
* @throws CertificateException If an exception occurs.
|
||||
*/
|
||||
public X509CertificatePair(X509Certificate forward, X509Certificate reverse)
|
||||
throws CertificateException {
|
||||
if (forward == null && reverse == null) {
|
||||
throw new CertificateException("at least one of certificate pair "
|
||||
+ "must be non-null");
|
||||
}
|
||||
|
||||
this.forward = forward;
|
||||
this.reverse = reverse;
|
||||
|
||||
checkPair();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new X509CertificatePair from its encoding.
|
||||
*
|
||||
* For internal use only, external code should use generateCertificatePair.
|
||||
*/
|
||||
private X509CertificatePair(byte[] encoded) throws CertificateException {
|
||||
try {
|
||||
parse(new DerValue(encoded));
|
||||
this.encoded = encoded;
|
||||
} catch (IOException ex) {
|
||||
throw new CertificateException(ex.toString());
|
||||
}
|
||||
checkPair();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the cache for debugging.
|
||||
*/
|
||||
public static synchronized void clearCache() {
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a X509CertificatePair from its encoding. Uses cache lookup
|
||||
* if possible.
|
||||
*/
|
||||
public static synchronized X509CertificatePair generateCertificatePair
|
||||
(byte[] encoded) throws CertificateException {
|
||||
Object key = new Cache.EqualByteArray(encoded);
|
||||
X509CertificatePair pair = cache.get(key);
|
||||
if (pair != null) {
|
||||
return pair;
|
||||
}
|
||||
pair = new X509CertificatePair(encoded);
|
||||
key = new Cache.EqualByteArray(pair.encoded);
|
||||
cache.put(key, pair);
|
||||
return pair;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the forward component of the certificate pair.
|
||||
*/
|
||||
public void setForward(X509Certificate cert) throws CertificateException {
|
||||
checkPair();
|
||||
forward = cert;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the reverse component of the certificate pair.
|
||||
*/
|
||||
public void setReverse(X509Certificate cert) throws CertificateException {
|
||||
checkPair();
|
||||
reverse = cert;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the forward component of the certificate pair.
|
||||
*
|
||||
* @return The forward certificate, or null if not set.
|
||||
*/
|
||||
public X509Certificate getForward() {
|
||||
return forward;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reverse component of the certificate pair.
|
||||
*
|
||||
* @return The reverse certificate, or null if not set.
|
||||
*/
|
||||
public X509Certificate getReverse() {
|
||||
return reverse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DER encoded form of the certificate pair.
|
||||
*
|
||||
* @return The encoded form of the certificate pair.
|
||||
* @throws CerticateEncodingException If an encoding exception occurs.
|
||||
*/
|
||||
public byte[] getEncoded() throws CertificateEncodingException {
|
||||
try {
|
||||
if (encoded == null) {
|
||||
DerOutputStream tmp = new DerOutputStream();
|
||||
emit(tmp);
|
||||
encoded = tmp.toByteArray();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new CertificateEncodingException(ex.toString());
|
||||
}
|
||||
return encoded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a printable representation of the certificate pair.
|
||||
*
|
||||
* @return A String describing the contents of the pair.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("X.509 Certificate Pair: [\n");
|
||||
if (forward != null)
|
||||
sb.append(" Forward: ").append(forward).append("\n");
|
||||
if (reverse != null)
|
||||
sb.append(" Reverse: ").append(reverse).append("\n");
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/* Parse the encoded bytes */
|
||||
private void parse(DerValue val)
|
||||
throws IOException, CertificateException
|
||||
{
|
||||
if (val.tag != DerValue.tag_Sequence) {
|
||||
throw new IOException
|
||||
("Sequence tag missing for X509CertificatePair");
|
||||
}
|
||||
|
||||
while (val.data != null && val.data.available() != 0) {
|
||||
DerValue opt = val.data.getDerValue();
|
||||
short tag = (byte) (opt.tag & 0x01f);
|
||||
switch (tag) {
|
||||
case TAG_FORWARD:
|
||||
if (opt.isContextSpecific() && opt.isConstructed()) {
|
||||
if (forward != null) {
|
||||
throw new IOException("Duplicate forward "
|
||||
+ "certificate in X509CertificatePair");
|
||||
}
|
||||
opt = opt.data.getDerValue();
|
||||
forward = X509Factory.intern
|
||||
(new X509CertImpl(opt.toByteArray()));
|
||||
}
|
||||
break;
|
||||
case TAG_REVERSE:
|
||||
if (opt.isContextSpecific() && opt.isConstructed()) {
|
||||
if (reverse != null) {
|
||||
throw new IOException("Duplicate reverse "
|
||||
+ "certificate in X509CertificatePair");
|
||||
}
|
||||
opt = opt.data.getDerValue();
|
||||
reverse = X509Factory.intern
|
||||
(new X509CertImpl(opt.toByteArray()));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IOException("Invalid encoding of "
|
||||
+ "X509CertificatePair");
|
||||
}
|
||||
}
|
||||
if (forward == null && reverse == null) {
|
||||
throw new CertificateException("at least one of certificate pair "
|
||||
+ "must be non-null");
|
||||
}
|
||||
}
|
||||
|
||||
/* Translate to encoded bytes */
|
||||
private void emit(DerOutputStream out)
|
||||
throws IOException, CertificateEncodingException
|
||||
{
|
||||
DerOutputStream tagged = new DerOutputStream();
|
||||
|
||||
if (forward != null) {
|
||||
DerOutputStream tmp = new DerOutputStream();
|
||||
tmp.putDerValue(new DerValue(forward.getEncoded()));
|
||||
tagged.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, TAG_FORWARD), tmp);
|
||||
}
|
||||
|
||||
if (reverse != null) {
|
||||
DerOutputStream tmp = new DerOutputStream();
|
||||
tmp.putDerValue(new DerValue(reverse.getEncoded()));
|
||||
tagged.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, TAG_REVERSE), tmp);
|
||||
}
|
||||
|
||||
out.write(DerValue.tag_Sequence, tagged);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for a valid certificate pair
|
||||
*/
|
||||
private void checkPair() throws CertificateException {
|
||||
|
||||
/* if either of pair is missing, return w/o error */
|
||||
if (forward == null || reverse == null) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* If both elements of the pair are present, check that they
|
||||
* are a valid pair.
|
||||
*/
|
||||
X500Principal fwSubject = forward.getSubjectX500Principal();
|
||||
X500Principal fwIssuer = forward.getIssuerX500Principal();
|
||||
X500Principal rvSubject = reverse.getSubjectX500Principal();
|
||||
X500Principal rvIssuer = reverse.getIssuerX500Principal();
|
||||
if (!fwIssuer.equals(rvSubject) || !rvIssuer.equals(fwSubject)) {
|
||||
throw new CertificateException("subject and issuer names in "
|
||||
+ "forward and reverse certificates do not match");
|
||||
}
|
||||
|
||||
/* check signatures unless key parameters are missing */
|
||||
try {
|
||||
PublicKey pk = reverse.getPublicKey();
|
||||
if (!(pk instanceof DSAPublicKey) ||
|
||||
((DSAPublicKey)pk).getParams() != null) {
|
||||
forward.verify(pk);
|
||||
}
|
||||
pk = forward.getPublicKey();
|
||||
if (!(pk instanceof DSAPublicKey) ||
|
||||
((DSAPublicKey)pk).getParams() != null) {
|
||||
reverse.verify(pk);
|
||||
}
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new CertificateException("invalid signature: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
1152
jdkSrc/jdk8/sun/security/provider/certpath/ldap/LDAPCertStore.java
Normal file
1152
jdkSrc/jdk8/sun/security/provider/certpath/ldap/LDAPCertStore.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath.ldap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.cert.CertStore;
|
||||
import java.security.cert.CertStoreException;
|
||||
import java.security.cert.X509CertSelector;
|
||||
import java.security.cert.X509CRLSelector;
|
||||
import javax.naming.CommunicationException;
|
||||
import javax.naming.ServiceUnavailableException;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
import sun.security.provider.certpath.CertStoreHelper;
|
||||
|
||||
/**
|
||||
* LDAP implementation of CertStoreHelper.
|
||||
*/
|
||||
|
||||
public final class LDAPCertStoreHelper
|
||||
extends CertStoreHelper
|
||||
{
|
||||
@Override
|
||||
public CertStore getCertStore(URI uri)
|
||||
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException
|
||||
{
|
||||
return LDAPCertStore.getInstance(LDAPCertStore.getParameters(uri));
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509CertSelector wrap(X509CertSelector selector,
|
||||
X500Principal certSubject,
|
||||
String ldapDN)
|
||||
throws IOException
|
||||
{
|
||||
return new LDAPCertStore.LDAPCertSelector(selector, certSubject, ldapDN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509CRLSelector wrap(X509CRLSelector selector,
|
||||
Collection<X500Principal> certIssuers,
|
||||
String ldapDN)
|
||||
throws IOException
|
||||
{
|
||||
return new LDAPCertStore.LDAPCRLSelector(selector, certIssuers, ldapDN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCausedByNetworkIssue(CertStoreException e) {
|
||||
Throwable t = e.getCause();
|
||||
return (t != null && (t instanceof ServiceUnavailableException ||
|
||||
t instanceof CommunicationException));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath.ssl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.Provider;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertSelector;
|
||||
import java.security.cert.CertStore;
|
||||
import java.security.cert.CertStoreException;
|
||||
import java.security.cert.CertStoreParameters;
|
||||
import java.security.cert.CertStoreSpi;
|
||||
import java.security.cert.CRLSelector;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.cert.X509CRL;
|
||||
import java.net.Socket;
|
||||
import java.net.URLConnection;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
|
||||
/**
|
||||
* A CertStore that retrieves an SSL server's certificate chain.
|
||||
*/
|
||||
public final class SSLServerCertStore extends CertStoreSpi {
|
||||
|
||||
private final URI uri;
|
||||
private final static GetChainTrustManager trustManager;
|
||||
private final static SSLSocketFactory socketFactory;
|
||||
private final static HostnameVerifier hostnameVerifier;
|
||||
|
||||
static {
|
||||
trustManager = new GetChainTrustManager();
|
||||
hostnameVerifier = new HostnameVerifier() {
|
||||
public boolean verify(String hostname, SSLSession session) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
SSLSocketFactory tempFactory;
|
||||
try {
|
||||
SSLContext context = SSLContext.getInstance("SSL");
|
||||
context.init(null, new TrustManager[] { trustManager }, null);
|
||||
tempFactory = context.getSocketFactory();
|
||||
} catch (GeneralSecurityException gse) {
|
||||
tempFactory = null;
|
||||
}
|
||||
|
||||
socketFactory = tempFactory;
|
||||
}
|
||||
|
||||
SSLServerCertStore(URI uri) throws InvalidAlgorithmParameterException {
|
||||
super(null);
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public Collection<X509Certificate> engineGetCertificates
|
||||
(CertSelector selector) throws CertStoreException {
|
||||
|
||||
try {
|
||||
URLConnection urlConn = uri.toURL().openConnection();
|
||||
if (urlConn instanceof HttpsURLConnection) {
|
||||
if (socketFactory == null) {
|
||||
throw new CertStoreException(
|
||||
"No initialized SSLSocketFactory");
|
||||
}
|
||||
|
||||
HttpsURLConnection https = (HttpsURLConnection)urlConn;
|
||||
https.setSSLSocketFactory(socketFactory);
|
||||
https.setHostnameVerifier(hostnameVerifier);
|
||||
synchronized (trustManager) {
|
||||
try {
|
||||
https.connect();
|
||||
return getMatchingCerts(
|
||||
trustManager.serverChain, selector);
|
||||
} catch (IOException ioe) {
|
||||
// If the server certificate has already been
|
||||
// retrieved, don't mind the connection state.
|
||||
if (trustManager.exchangedServerCerts) {
|
||||
return getMatchingCerts(
|
||||
trustManager.serverChain, selector);
|
||||
}
|
||||
|
||||
// otherwise, rethrow the exception
|
||||
throw ioe;
|
||||
} finally {
|
||||
trustManager.cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new CertStoreException(ioe);
|
||||
}
|
||||
|
||||
return Collections.<X509Certificate>emptySet();
|
||||
}
|
||||
|
||||
private static List<X509Certificate> getMatchingCerts
|
||||
(List<X509Certificate> certs, CertSelector selector)
|
||||
{
|
||||
// if selector not specified, all certs match
|
||||
if (selector == null) {
|
||||
return certs;
|
||||
}
|
||||
List<X509Certificate> matchedCerts = new ArrayList<>(certs.size());
|
||||
for (X509Certificate cert : certs) {
|
||||
if (selector.match(cert)) {
|
||||
matchedCerts.add(cert);
|
||||
}
|
||||
}
|
||||
return matchedCerts;
|
||||
}
|
||||
|
||||
public Collection<X509CRL> engineGetCRLs(CRLSelector selector)
|
||||
throws CertStoreException
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
static CertStore getInstance(URI uri)
|
||||
throws InvalidAlgorithmParameterException
|
||||
{
|
||||
return new CS(new SSLServerCertStore(uri), null, "SSLServer", null);
|
||||
}
|
||||
|
||||
/*
|
||||
* An X509ExtendedTrustManager that ignores the server certificate
|
||||
* validation.
|
||||
*/
|
||||
private static class GetChainTrustManager
|
||||
extends X509ExtendedTrustManager {
|
||||
|
||||
private List<X509Certificate> serverChain =
|
||||
Collections.<X509Certificate>emptyList();
|
||||
private boolean exchangedServerCerts = false;
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] chain,
|
||||
String authType) throws CertificateException {
|
||||
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType,
|
||||
Socket socket) throws CertificateException {
|
||||
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType,
|
||||
SSLEngine engine) throws CertificateException {
|
||||
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] chain,
|
||||
String authType) throws CertificateException {
|
||||
|
||||
exchangedServerCerts = true;
|
||||
this.serverChain = (chain == null)
|
||||
? Collections.<X509Certificate>emptyList()
|
||||
: Arrays.<X509Certificate>asList(chain);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType,
|
||||
Socket socket) throws CertificateException {
|
||||
|
||||
checkServerTrusted(chain, authType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType,
|
||||
SSLEngine engine) throws CertificateException {
|
||||
|
||||
checkServerTrusted(chain, authType);
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
exchangedServerCerts = false;
|
||||
serverChain = Collections.<X509Certificate>emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class allows the SSLServerCertStore to be accessed as a CertStore.
|
||||
*/
|
||||
private static class CS extends CertStore {
|
||||
protected CS(CertStoreSpi spi, Provider p, String type,
|
||||
CertStoreParameters params)
|
||||
{
|
||||
super(spi, p, type, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider.certpath.ssl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.cert.CertStore;
|
||||
import java.security.cert.CertStoreException;
|
||||
import java.security.cert.X509CertSelector;
|
||||
import java.security.cert.X509CRLSelector;
|
||||
import java.util.Collection;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
import sun.security.provider.certpath.CertStoreHelper;
|
||||
|
||||
/**
|
||||
* SSL implementation of CertStoreHelper.
|
||||
*/
|
||||
public final class SSLServerCertStoreHelper extends CertStoreHelper {
|
||||
|
||||
@Override
|
||||
public CertStore getCertStore(URI uri)
|
||||
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException
|
||||
{
|
||||
return SSLServerCertStore.getInstance(uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509CertSelector wrap(X509CertSelector selector,
|
||||
X500Principal certSubject,
|
||||
String ldapDN)
|
||||
throws IOException
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509CRLSelector wrap(X509CRLSelector selector,
|
||||
Collection<X500Principal> certIssuers,
|
||||
String ldapDN)
|
||||
throws IOException
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCausedByNetworkIssue(CertStoreException e) {
|
||||
Throwable t = e.getCause();
|
||||
return (t != null && t instanceof IOException);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user