org.apache.ws.security.components.crypto.DERDecoder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of wss4j Show documentation
Show all versions of wss4j Show documentation
The Apache WSS4J project provides a Java implementation of the primary security standards
for Web Services, namely the OASIS Web Services Security (WS-Security) specifications
from the OASIS Web Services Security TC.
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.ws.security.components.crypto;
import java.math.BigInteger;
import org.apache.ws.security.WSSecurityException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Provides the means to navigate through a DER-encoded byte array, to help
* in decoding the contents.
*
* It maintains a "current position" in the array that advances with each
* operation, providing a simple means to handle the type-length-value
* encoding of DER. For example
*
* decoder.expect(TYPE);
* int length = decoder.getLength();
* byte[] value = decoder.getBytes(len);
*
*/
public class DERDecoder {
private static Log log = LogFactory.getLog(DERDecoder.class);
/** DER type identifier for a bit string value */
public static final byte TYPE_BIT_STRING = 0x03;
/** DER type identifier for a octet string value */
public static final byte TYPE_OCTET_STRING = 0x04;
/** DER type identifier for a sequence value */
public static final byte TYPE_SEQUENCE = 0x30;
private byte[] arr;
private int pos;
/**
* Construct a DERDecoder for the given byte array.
*
* @param derEncoded the DER-encoded array to decode.
* @throws WSSecurityException if the given array is null.
*/
public DERDecoder(byte[] derEncoded) throws WSSecurityException {
if (derEncoded == null) {
throw new WSSecurityException(
WSSecurityException.UNSUPPORTED_SECURITY_TOKEN,
"noSKIHandling",
new Object[] { "Invalid DER string" }
);
}
arr = derEncoded;
reset();
}
/**
* Reset the current position to the start of the array.
*/
public void reset() {
pos = 0;
}
/**
* Advance the current position by the given number of bytes.
*
* @param length the number of bytes to skip.
* @throws WSSecurityException if length is negative.
*/
public void skip(int length) throws WSSecurityException {
if (length < 0) {
throw new WSSecurityException(
WSSecurityException.UNSUPPORTED_SECURITY_TOKEN,
"noSKIHandling",
new Object[] { "Unsupported DER format" }
);
}
pos += length;
}
/**
* Confirm that the byte at the current position matches the given value.
*
* @param val the expected next byte.
* @throws WSSecurityException
* if the current position is at the end of the array, or if the
* byte at the current position doesn't match the expected value.
*/
public void expect(int val) throws WSSecurityException {
expect((byte)(val & 0xFF));
}
/**
* Confirm that the byte at the current position matches the given value.
*
* @param val the expected next byte.
* @throws WSSecurityException
* if the current position is at the end of the array, or if the
* byte at the current position doesn't match the expected value.
*/
public void expect(byte val) throws WSSecurityException {
if (!test(val)) {
log.debug("DER mismatch: expected " + val + ", got " + arr[pos]);
throw new WSSecurityException(
WSSecurityException.UNSUPPORTED_SECURITY_TOKEN,
"noSKIHandling",
new Object[] { "Invalid DER format" }
);
}
pos++;
}
/**
* Test if the byte at the current position matches the given value.
*
* @param val the value to test for a match with the current byte.
* @return true if the byte at the current position matches the given value.
* @throws WSSecurityException if the current position is at the end of
* the array.
*/
public boolean test(byte val) throws WSSecurityException {
if (pos >= arr.length) {
throw new WSSecurityException(
WSSecurityException.UNSUPPORTED_SECURITY_TOKEN,
"noSKIHandling",
new Object[] { "Invalid DER format" }
);
}
return (arr[pos] == val);
}
/**
* Get the DER length at the current position.
*
* DER length is encoded as
*
* - If the first byte is 0x00 to 0x7F, it describes the actual length.
*
- If the first byte is 0x80 + n with 0
The length value 0x80, used only in constructed types, is
* defined as "indefinite length".
*
*
* @return the length, -1 for indefinite length.
* @throws WSSecurityException
* if the current position is at the end of the array or there is
* an incomplete length specification.
*/
public int getLength() throws WSSecurityException {
if (pos >= arr.length) {
throw new WSSecurityException(
WSSecurityException.UNSUPPORTED_SECURITY_TOKEN,
"noSKIHandling",
new Object[] { "Invalid DER format" }
);
}
int len;
if ((arr[pos] & 0xFF) <= 0x7F) {
len = arr[pos++];
} else if (arr[pos] == 0x80) {
len = -1;
pos++;
} else {
int nbytes = arr[pos++] & 0x7F;
if (pos + nbytes > arr.length) {
throw new WSSecurityException(
WSSecurityException.UNSUPPORTED_SECURITY_TOKEN,
"noSKIHandling",
new Object[] { "Invalid DER format" }
);
}
byte[] lenBytes = new byte[nbytes];
System.arraycopy(arr, pos, lenBytes, 0, lenBytes.length);
len = new BigInteger(1, lenBytes).intValue();
pos += nbytes;
}
return len;
}
/**
* Return an array of bytes from the current position.
*
* @param length the number of bytes to return.
* @return an array of the requested number of bytes from the current
* position.
* @throws WSSecurityException
* if the current position is at the end of the array, or the
* length is negative.
*/
public byte[] getBytes(int length) throws WSSecurityException {
if (pos + length > arr.length) {
throw new WSSecurityException(
WSSecurityException.UNSUPPORTED_SECURITY_TOKEN,
"noSKIHandling",
new Object[] { "Invalid DER format" }
);
} else if (length < 0) {
throw new WSSecurityException(
WSSecurityException.UNSUPPORTED_SECURITY_TOKEN,
"noSKIHandling",
new Object[] { "Unsupported DER format" }
);
}
byte[] value = new byte[length];
System.arraycopy(arr, pos, value, 0, length);
pos += length;
return value;
}
}