feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
532
jdkSrc/jdk8/sun/security/jgss/krb5/WrapToken.java
Normal file
532
jdkSrc/jdk8/sun/security/jgss/krb5/WrapToken.java
Normal file
@@ -0,0 +1,532 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, 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.jgss.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import sun.security.krb5.Confounder;
|
||||
|
||||
/**
|
||||
* This class represents a token emitted by the GSSContext.wrap()
|
||||
* call. It is a MessageToken except that it also contains plaintext
|
||||
* or encrypted data at the end. A wrapToken has certain other rules
|
||||
* that are peculiar to it and different from a MICToken, which is
|
||||
* another type of MessageToken. All data in a WrapToken is prepended
|
||||
* by a random counfounder of 8 bytes. All data in a WrapToken is
|
||||
* also padded with one to eight bytes where all bytes are equal in
|
||||
* value to the number of bytes being padded. Thus, all application
|
||||
* data is replaced by (confounder || data || padding).
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
*/
|
||||
class WrapToken extends MessageToken {
|
||||
/**
|
||||
* The size of the random confounder used in a WrapToken.
|
||||
*/
|
||||
static final int CONFOUNDER_SIZE = 8;
|
||||
|
||||
/*
|
||||
* The padding used with a WrapToken. All data is padded to the
|
||||
* next multiple of 8 bytes, even if its length is already
|
||||
* multiple of 8.
|
||||
* Use this table as a quick way to obtain padding bytes by
|
||||
* indexing it with the number of padding bytes required.
|
||||
*/
|
||||
static final byte[][] pads = {
|
||||
null, // No, no one escapes padding
|
||||
{0x01},
|
||||
{0x02, 0x02},
|
||||
{0x03, 0x03, 0x03},
|
||||
{0x04, 0x04, 0x04, 0x04},
|
||||
{0x05, 0x05, 0x05, 0x05, 0x05},
|
||||
{0x06, 0x06, 0x06, 0x06, 0x06, 0x06},
|
||||
{0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07},
|
||||
{0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}
|
||||
};
|
||||
|
||||
/*
|
||||
* A token may come in either in an InputStream or as a
|
||||
* byte[]. Store a reference to it in either case and process
|
||||
* it's data only later when getData() is called and
|
||||
* decryption/copying is needed to be done. Note that JCE can
|
||||
* decrypt both from a byte[] and from an InputStream.
|
||||
*/
|
||||
private boolean readTokenFromInputStream = true;
|
||||
private InputStream is = null;
|
||||
private byte[] tokenBytes = null;
|
||||
private int tokenOffset = 0;
|
||||
private int tokenLen = 0;
|
||||
|
||||
/*
|
||||
* Application data may come from an InputStream or from a
|
||||
* byte[]. However, it will always be stored and processed as a
|
||||
* byte[] since
|
||||
* (a) the MessageDigest class only accepts a byte[] as input and
|
||||
* (b) It allows writing to an OuputStream via a CipherOutputStream.
|
||||
*/
|
||||
private byte[] dataBytes = null;
|
||||
private int dataOffset = 0;
|
||||
private int dataLen = 0;
|
||||
|
||||
// the len of the token data: (confounder || data || padding)
|
||||
private int dataSize = 0;
|
||||
|
||||
// Accessed by CipherHelper
|
||||
byte[] confounder = null;
|
||||
byte[] padding = null;
|
||||
|
||||
private boolean privacy = false;
|
||||
|
||||
/**
|
||||
* Constructs a WrapToken from token bytes obtained from the
|
||||
* peer.
|
||||
* @param context the mechanism context associated with this
|
||||
* token
|
||||
* @param tokenBytes the bytes of the token
|
||||
* @param tokenOffset the offset of the token
|
||||
* @param tokenLen the length of the token
|
||||
* @param prop the MessageProp into which characteristics of the
|
||||
* parsed token will be stored.
|
||||
* @throws GSSException if the token is defective
|
||||
*/
|
||||
public WrapToken(Krb5Context context,
|
||||
byte[] tokenBytes, int tokenOffset, int tokenLen,
|
||||
MessageProp prop) throws GSSException {
|
||||
|
||||
// Just parse the MessageToken part first
|
||||
super(Krb5Token.WRAP_ID, context,
|
||||
tokenBytes, tokenOffset, tokenLen, prop);
|
||||
|
||||
this.readTokenFromInputStream = false;
|
||||
|
||||
// Will need the token bytes again when extracting data
|
||||
this.tokenBytes = tokenBytes;
|
||||
this.tokenOffset = tokenOffset;
|
||||
this.tokenLen = tokenLen;
|
||||
this.privacy = prop.getPrivacy();
|
||||
dataSize =
|
||||
getGSSHeader().getMechTokenLength() - getKrb5TokenSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a WrapToken from token bytes read on the fly from
|
||||
* an InputStream.
|
||||
* @param context the mechanism context associated with this
|
||||
* token
|
||||
* @param is the InputStream containing the token bytes
|
||||
* @param prop the MessageProp into which characteristics of the
|
||||
* parsed token will be stored.
|
||||
* @throws GSSException if the token is defective or if there is
|
||||
* a problem reading from the InputStream
|
||||
*/
|
||||
public WrapToken(Krb5Context context,
|
||||
InputStream is, MessageProp prop)
|
||||
throws GSSException {
|
||||
|
||||
// Just parse the MessageToken part first
|
||||
super(Krb5Token.WRAP_ID, context, is, prop);
|
||||
|
||||
// Will need the token bytes again when extracting data
|
||||
this.is = is;
|
||||
this.privacy = prop.getPrivacy();
|
||||
/*
|
||||
debug("WrapToken Cons: gssHeader.getMechTokenLength=" +
|
||||
getGSSHeader().getMechTokenLength());
|
||||
debug("\n token size="
|
||||
+ getTokenSize());
|
||||
*/
|
||||
|
||||
dataSize =
|
||||
getGSSHeader().getMechTokenLength() - getTokenSize();
|
||||
// debug("\n dataSize=" + dataSize);
|
||||
// debug("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the application data that was transmitted in this
|
||||
* WrapToken.
|
||||
* @return a byte array containing the application data
|
||||
* @throws GSSException if an error occurs while decrypting any
|
||||
* cipher text and checking for validity
|
||||
*/
|
||||
public byte[] getData() throws GSSException {
|
||||
|
||||
byte[] temp = new byte[dataSize];
|
||||
getData(temp, 0);
|
||||
|
||||
// Remove the confounder and the padding
|
||||
byte[] retVal = new byte[dataSize - confounder.length -
|
||||
padding.length];
|
||||
System.arraycopy(temp, 0, retVal, 0, retVal.length);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the application data that was transmitted in this
|
||||
* WrapToken, writing it into an application provided output
|
||||
* array.
|
||||
* @param dataBuf the output buffer into which the data must be
|
||||
* written
|
||||
* @param dataBufOffset the offset at which to write the data
|
||||
* @return the size of the data written
|
||||
* @throws GSSException if an error occurs while decrypting any
|
||||
* cipher text and checking for validity
|
||||
*/
|
||||
public int getData(byte[] dataBuf, int dataBufOffset)
|
||||
throws GSSException {
|
||||
|
||||
if (readTokenFromInputStream)
|
||||
getDataFromStream(dataBuf, dataBufOffset);
|
||||
else
|
||||
getDataFromBuffer(dataBuf, dataBufOffset);
|
||||
|
||||
return (dataSize - confounder.length - padding.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper routine to obtain the application data transmitted in
|
||||
* this WrapToken. It is called if the WrapToken was constructed
|
||||
* with a byte array as input.
|
||||
* @param dataBuf the output buffer into which the data must be
|
||||
* written
|
||||
* @param dataBufOffset the offset at which to write the data
|
||||
* @throws GSSException if an error occurs while decrypting any
|
||||
* cipher text and checking for validity
|
||||
*/
|
||||
private void getDataFromBuffer(byte[] dataBuf, int dataBufOffset)
|
||||
throws GSSException {
|
||||
|
||||
GSSHeader gssHeader = getGSSHeader();
|
||||
int dataPos = tokenOffset +
|
||||
gssHeader.getLength() + getTokenSize();
|
||||
|
||||
if (dataPos + dataSize > tokenOffset + tokenLen)
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
"Insufficient data in "
|
||||
+ getTokenName(getTokenId()));
|
||||
|
||||
// debug("WrapToken cons: data is token is [" +
|
||||
// getHexBytes(tokenBytes, tokenOffset, tokenLen) + "]\n");
|
||||
|
||||
confounder = new byte[CONFOUNDER_SIZE];
|
||||
|
||||
// Do decryption if this token was privacy protected.
|
||||
|
||||
if (privacy) {
|
||||
cipherHelper.decryptData(this,
|
||||
tokenBytes, dataPos, dataSize, dataBuf, dataBufOffset);
|
||||
/*
|
||||
debug("\t\tDecrypted data is [" +
|
||||
getHexBytes(confounder) + " " +
|
||||
getHexBytes(dataBuf, dataBufOffset,
|
||||
dataSize - CONFOUNDER_SIZE - padding.length) +
|
||||
getHexBytes(padding) +
|
||||
"]\n");
|
||||
*/
|
||||
|
||||
} else {
|
||||
|
||||
// Token data is in cleartext
|
||||
// debug("\t\tNo encryption was performed by peer.\n");
|
||||
System.arraycopy(tokenBytes, dataPos,
|
||||
confounder, 0, CONFOUNDER_SIZE);
|
||||
int padSize = tokenBytes[dataPos + dataSize - 1];
|
||||
if (padSize < 0)
|
||||
padSize = 0;
|
||||
if (padSize > 8)
|
||||
padSize %= 8;
|
||||
|
||||
padding = pads[padSize];
|
||||
// debug("\t\tPadding applied was: " + padSize + "\n");
|
||||
|
||||
System.arraycopy(tokenBytes, dataPos + CONFOUNDER_SIZE,
|
||||
dataBuf, dataBufOffset, dataSize -
|
||||
CONFOUNDER_SIZE - padSize);
|
||||
|
||||
// byte[] debugbuf = new byte[dataSize - CONFOUNDER_SIZE - padSize];
|
||||
// System.arraycopy(tokenBytes, dataPos + CONFOUNDER_SIZE,
|
||||
// debugbuf, 0, debugbuf.length);
|
||||
// debug("\t\tData is: " + getHexBytes(debugbuf, debugbuf.length));
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure sign and sequence number are not corrupt
|
||||
*/
|
||||
|
||||
if (!verifySignAndSeqNumber(confounder,
|
||||
dataBuf, dataBufOffset,
|
||||
dataSize - CONFOUNDER_SIZE
|
||||
- padding.length,
|
||||
padding))
|
||||
throw new GSSException(GSSException.BAD_MIC, -1,
|
||||
"Corrupt checksum or sequence number in Wrap token");
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper routine to obtain the application data transmitted in
|
||||
* this WrapToken. It is called if the WrapToken was constructed
|
||||
* with an Inputstream.
|
||||
* @param dataBuf the output buffer into which the data must be
|
||||
* written
|
||||
* @param dataBufOffset the offset at which to write the data
|
||||
* @throws GSSException if an error occurs while decrypting any
|
||||
* cipher text and checking for validity
|
||||
*/
|
||||
private void getDataFromStream(byte[] dataBuf, int dataBufOffset)
|
||||
throws GSSException {
|
||||
|
||||
GSSHeader gssHeader = getGSSHeader();
|
||||
|
||||
// Don't check the token length. Data will be read on demand from
|
||||
// the InputStream.
|
||||
|
||||
// debug("WrapToken cons: data will be read from InputStream.\n");
|
||||
|
||||
confounder = new byte[CONFOUNDER_SIZE];
|
||||
|
||||
try {
|
||||
|
||||
// Do decryption if this token was privacy protected.
|
||||
|
||||
if (privacy) {
|
||||
cipherHelper.decryptData(this, is, dataSize,
|
||||
dataBuf, dataBufOffset);
|
||||
|
||||
// debug("\t\tDecrypted data is [" +
|
||||
// getHexBytes(confounder) + " " +
|
||||
// getHexBytes(dataBuf, dataBufOffset,
|
||||
// dataSize - CONFOUNDER_SIZE - padding.length) +
|
||||
// getHexBytes(padding) +
|
||||
// "]\n");
|
||||
|
||||
} else {
|
||||
|
||||
// Token data is in cleartext
|
||||
// debug("\t\tNo encryption was performed by peer.\n");
|
||||
readFully(is, confounder);
|
||||
|
||||
if (cipherHelper.isArcFour()) {
|
||||
padding = pads[1];
|
||||
readFully(is, dataBuf, dataBufOffset, dataSize-CONFOUNDER_SIZE-1);
|
||||
} else {
|
||||
// Data is always a multiple of 8 with this GSS Mech
|
||||
// Copy all but last block as they are
|
||||
int numBlocks = (dataSize - CONFOUNDER_SIZE)/8 - 1;
|
||||
int offset = dataBufOffset;
|
||||
for (int i = 0; i < numBlocks; i++) {
|
||||
readFully(is, dataBuf, offset, 8);
|
||||
offset += 8;
|
||||
}
|
||||
|
||||
byte[] finalBlock = new byte[8];
|
||||
readFully(is, finalBlock);
|
||||
|
||||
int padSize = finalBlock[7];
|
||||
padding = pads[padSize];
|
||||
|
||||
// debug("\t\tPadding applied was: " + padSize + "\n");
|
||||
System.arraycopy(finalBlock, 0, dataBuf, offset,
|
||||
finalBlock.length - padSize);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(getTokenId())
|
||||
+ ": " + e.getMessage());
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure sign and sequence number are not corrupt
|
||||
*/
|
||||
|
||||
if (!verifySignAndSeqNumber(confounder,
|
||||
dataBuf, dataBufOffset,
|
||||
dataSize - CONFOUNDER_SIZE
|
||||
- padding.length,
|
||||
padding))
|
||||
throw new GSSException(GSSException.BAD_MIC, -1,
|
||||
"Corrupt checksum or sequence number in Wrap token");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper routine to pick the right padding for a certain length
|
||||
* of application data. Every application message has some
|
||||
* padding between 1 and 8 bytes.
|
||||
* @param len the length of the application data
|
||||
* @return the padding to be applied
|
||||
*/
|
||||
private byte[] getPadding(int len) {
|
||||
int padSize = 0;
|
||||
// For RC4-HMAC, all padding is rounded up to 1 byte.
|
||||
// One byte is needed to say that there is 1 byte of padding.
|
||||
if (cipherHelper.isArcFour()) {
|
||||
padSize = 1;
|
||||
} else {
|
||||
padSize = len % 8;
|
||||
padSize = 8 - padSize;
|
||||
}
|
||||
return pads[padSize];
|
||||
}
|
||||
|
||||
public WrapToken(Krb5Context context, MessageProp prop,
|
||||
byte[] dataBytes, int dataOffset, int dataLen)
|
||||
throws GSSException {
|
||||
|
||||
super(Krb5Token.WRAP_ID, context);
|
||||
|
||||
confounder = Confounder.bytes(CONFOUNDER_SIZE);
|
||||
|
||||
padding = getPadding(dataLen);
|
||||
dataSize = confounder.length + dataLen + padding.length;
|
||||
this.dataBytes = dataBytes;
|
||||
this.dataOffset = dataOffset;
|
||||
this.dataLen = dataLen;
|
||||
|
||||
/*
|
||||
debug("\nWrapToken cons: data to wrap is [" +
|
||||
getHexBytes(confounder) + " " +
|
||||
getHexBytes(dataBytes, dataOffset, dataLen) + " " +
|
||||
// padding is never null for Wrap
|
||||
getHexBytes(padding) + "]\n");
|
||||
*/
|
||||
|
||||
genSignAndSeqNumber(prop,
|
||||
confounder,
|
||||
dataBytes, dataOffset, dataLen,
|
||||
padding);
|
||||
|
||||
/*
|
||||
* If the application decides to ask for privacy when the context
|
||||
* did not negotiate for it, do not provide it. The peer might not
|
||||
* have support for it. The app will realize this with a call to
|
||||
* pop.getPrivacy() after wrap().
|
||||
*/
|
||||
if (!context.getConfState())
|
||||
prop.setPrivacy(false);
|
||||
|
||||
privacy = prop.getPrivacy();
|
||||
}
|
||||
|
||||
public void encode(OutputStream os) throws IOException, GSSException {
|
||||
|
||||
super.encode(os);
|
||||
|
||||
// debug("Writing data: [");
|
||||
if (!privacy) {
|
||||
|
||||
// debug(getHexBytes(confounder, confounder.length));
|
||||
os.write(confounder);
|
||||
|
||||
// debug(" " + getHexBytes(dataBytes, dataOffset, dataLen));
|
||||
os.write(dataBytes, dataOffset, dataLen);
|
||||
|
||||
// debug(" " + getHexBytes(padding, padding.length));
|
||||
os.write(padding);
|
||||
|
||||
} else {
|
||||
|
||||
cipherHelper.encryptData(this, confounder,
|
||||
dataBytes, dataOffset, dataLen, padding, os);
|
||||
}
|
||||
// debug("]\n");
|
||||
}
|
||||
|
||||
public byte[] encode() throws IOException, GSSException {
|
||||
// XXX Fine tune this initial size
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(dataSize + 50);
|
||||
encode(bos);
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
public int encode(byte[] outToken, int offset)
|
||||
throws IOException, GSSException {
|
||||
|
||||
// Token header is small
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
super.encode(bos);
|
||||
byte[] header = bos.toByteArray();
|
||||
System.arraycopy(header, 0, outToken, offset, header.length);
|
||||
offset += header.length;
|
||||
|
||||
// debug("WrapToken.encode: Writing data: [");
|
||||
if (!privacy) {
|
||||
|
||||
// debug(getHexBytes(confounder, confounder.length));
|
||||
System.arraycopy(confounder, 0, outToken, offset,
|
||||
confounder.length);
|
||||
offset += confounder.length;
|
||||
|
||||
// debug(" " + getHexBytes(dataBytes, dataOffset, dataLen));
|
||||
System.arraycopy(dataBytes, dataOffset, outToken, offset,
|
||||
dataLen);
|
||||
offset += dataLen;
|
||||
|
||||
// debug(" " + getHexBytes(padding, padding.length));
|
||||
System.arraycopy(padding, 0, outToken, offset, padding.length);
|
||||
|
||||
} else {
|
||||
|
||||
cipherHelper.encryptData(this, confounder, dataBytes,
|
||||
dataOffset, dataLen, padding, outToken, offset);
|
||||
|
||||
// debug(getHexBytes(outToken, offset, dataSize));
|
||||
}
|
||||
|
||||
// debug("]\n");
|
||||
|
||||
// %%% assume that plaintext length == ciphertext len
|
||||
return (header.length + confounder.length + dataLen + padding.length);
|
||||
|
||||
}
|
||||
|
||||
protected int getKrb5TokenSize() throws GSSException {
|
||||
return (getTokenSize() + dataSize);
|
||||
}
|
||||
|
||||
protected int getSealAlg(boolean conf, int qop) throws GSSException {
|
||||
if (!conf) {
|
||||
return SEAL_ALG_NONE;
|
||||
}
|
||||
|
||||
// ignore QOP
|
||||
return cipherHelper.getSealAlg();
|
||||
}
|
||||
|
||||
// This implementation is way too conservative. And it certainly
|
||||
// doesn't return the maximum limit.
|
||||
static int getSizeLimit(int qop, boolean confReq, int maxTokenSize,
|
||||
CipherHelper ch) throws GSSException {
|
||||
return (GSSHeader.getMaxMechTokenSize(OID, maxTokenSize) -
|
||||
(getTokenSize(ch) + CONFOUNDER_SIZE) - 8); /* safety */
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user