blob: 57b9852266c48bfec576f7053e9d09d51084b003 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2007 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.osgi.internal.signedcontent;
import java.math.BigInteger;
import java.security.SignatureException;
/**
* This is a simple class that processes BER structures. This class
* uses BER processing as outlined in X.690.
*/
public class BERProcessor {
/**
* This is the buffer that contains the BER structures that are being interrogated.
*/
byte buffer[];
/**
* The offset into <code>buffer</code> to the start of the structure being interrogated.
* If the offset is -1 that means that we have read the last structure.
*/
int offset;
/**
* The last valid offset in <code>buffer</code>.
*/
int lastOffset;
/**
* The offset into <code>buffer</code> to the start of the content of the structure
* being interrogated.
*/
int contentOffset;
/**
* The length of the content of the structure being interrogated.
*/
int contentLength;
/**
* The offset into <code>buffer</code> of the end of the structure being interrogated.
*/
int endOffset;
/**
* The class of the tag of the current structure.
*/
int classOfTag;
static final int UNIVERSAL_TAGCLASS = 0;
static final int APPLICATION_TAGCLASS = 1;
static final int CONTEXTSPECIFIC_TAGCLASS = 2;
static final int PRIVATE_TAGCLASS = 3;
static final byte BOOLTAG = 1;
static final byte INTTAG = 2;
static final byte OIDTAG = 6;
static final byte SEQTAG = 16;
static final byte SETTAG = 17;
static final byte NULLTAG = 5;
/**
* Tagnames used in toString()
*/
static final String tagNames[] = {"<null>", "boolean", "int", "bitstring", "octetstring", "null", "objid", "objdesc", "external", "real", "enum", "pdv", "utf8", "relobjid", "resv", "resv", "sequence", "set", "char string"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$ //$NON-NLS-12$ //$NON-NLS-13$ //$NON-NLS-14$ //$NON-NLS-15$ //$NON-NLS-16$ //$NON-NLS-17$ //$NON-NLS-18$ //$NON-NLS-19$
/**
* True if this is a structure for a constructed encoding.
*/
public boolean constructed;
/**
* The tag type. Note that X.690 specifies encodings for tags with values greater than 31,
* but currently this class does not handle these kinds of tags.
*/
public byte tag;
/**
* Constructs a BERProcessor to operate on the passed buffer. The first structure in the
* buffer will be processed before this method returns.
*
* @param buffer the buffer containing the BER structures.
* @param offset the offset into <code>buffer</code> to the start of the first structure.
* @param len the length of the BER structure.
* @throws SignatureException
*/
public BERProcessor(byte buffer[], int offset, int len) throws SignatureException {
this.buffer = buffer;
this.offset = offset;
lastOffset = len + offset;
processStructure();
}
/**
* Parse the structure found at the current <code>offset</code> into <code>buffer</code>.
* Most methods, constructor, and stepinto, will call this method automatically. If
* <code>offset</code> is modified outside of those methods, this method will need to
* be invoked.
*/
public void processStructure() throws SignatureException {
// Don't process if we are at the end
if (offset == -1)
return;
endOffset = offset;
// section 8.1.2.2
classOfTag = (buffer[offset] & 0xff) >> 6;
// section 8.1.2.5
constructed = (buffer[offset] & 0x20) != 0;
// section 8.1.2.3
byte tagNumber = (byte) (buffer[offset] & 0x1f);
if (tagNumber < 32) {
tag = tagNumber;
endOffset = offset + 1;
} else {
throw new SignatureException("Can't handle tags > 32"); //$NON-NLS-1$
}
if ((buffer[endOffset] & 0x80) == 0) {
// section 8.1.3.4 (doing the short form of the length)
contentLength = buffer[endOffset];
endOffset++;
} else {
// section 8.1.3.5 (doing the long form of the length)
int octetCount = buffer[endOffset] & 0x7f;
if (octetCount > 3)
throw new SignatureException("ContentLength octet count too large: " + octetCount); //$NON-NLS-1$
contentLength = 0;
endOffset++;
for (int i = 0; i < octetCount; i++) {
contentLength <<= 8;
contentLength |= buffer[endOffset] & 0xff;
endOffset++;
}
// section 8.1.3.6 (doing the indefinite form
if (octetCount == 0)
contentLength = -1;
}
contentOffset = endOffset;
if (contentLength != -1)
endOffset += contentLength;
if (endOffset > lastOffset)
throw new SignatureException("Content length too large: " + endOffset + " > " + lastOffset); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Returns a String representation of the current BER structure.
* @return a String representation of the current BER structure.
* @see java.lang.Object#toString()
*/
public String toString() {
StringBuffer sb = new StringBuffer();
switch (classOfTag) {
case UNIVERSAL_TAGCLASS :
sb.append('U');
break;
case APPLICATION_TAGCLASS :
sb.append('A');
break;
case CONTEXTSPECIFIC_TAGCLASS :
sb.append('C');
break;
case PRIVATE_TAGCLASS :
sb.append('P');
break;
}
sb.append(constructed ? 'C' : 'P');
sb.append(" tag=" + tag); //$NON-NLS-1$
if (tag < tagNames.length) {
sb.append("(" + tagNames[tag] + ")"); //$NON-NLS-1$ //$NON-NLS-2$
}
sb.append(" len="); //$NON-NLS-1$
sb.append(contentLength);
switch (tag) {
case INTTAG :
sb.append(" value=" + getIntValue()); //$NON-NLS-1$
break;
case OIDTAG :
sb.append(" value="); //$NON-NLS-1$
int oid[] = getObjId();
for (int i = 0; i < oid.length; i++) {
if (i > 0)
sb.append('.');
sb.append(oid[i]);
}
}
if (tag == 12 || (tag >= 18 && tag <= 22) || (tag >= 25 && tag <= 30)) {
sb.append(" value="); //$NON-NLS-1$
sb.append(getString());
}
return sb.toString();
}
/**
* Returns a BERProcessor for the content of the current structure.
* @throws SignatureException
*/
public BERProcessor stepInto() throws SignatureException {
return new BERProcessor(buffer, contentOffset, contentLength);
}
public void stepOver() throws SignatureException {
offset = endOffset;
if (endOffset >= lastOffset) {
offset = -1;
return;
}
processStructure();
}
public boolean endOfSequence() {
return offset == -1;
}
/**
* Gets the content from the current structure as a String.
* @return the content from the current structure as a String.
*/
public String getString() {
return new String(buffer, contentOffset, contentLength);
}
/**
* Gets the content from the current structure as an int.
* @return the content from the current structure as an int.
*/
public BigInteger getIntValue() {
return new BigInteger(getBytes());
}
/**
* Gets the content from the current structure as an object id (int[]).
* @return the content from the current structure as an object id (int[]).
*/
public int[] getObjId() {
// First count the ids
int count = 0;
for (int i = 0; i < contentLength; i++) {
// section 8.19.2
if ((buffer[contentOffset + i] & 0x80) == 0)
count++;
}
count++; // section 8.19.3
int oid[] = new int[count];
int index = 0;
int currentValue = 0;
for (int i = 0; i < contentLength; i++) {
currentValue <<= 7;
currentValue |= buffer[contentOffset + i] & 0x7f;
// section 8.19.2
if ((buffer[contentOffset + i] & 0x80) == 0) {
if (index == 0) {
// section 8.19.4 special processing
oid[index++] = currentValue / 40;
oid[index++] = currentValue % 40;
} else {
oid[index++] = currentValue;
}
currentValue = 0;
}
}
return oid;
}
/**
* Get a copy of the bytes in the content of the current structure.
* @return a copy of the bytes in the content of the current structure.
*/
public byte[] getBytes() {
byte v[] = new byte[contentLength];
System.arraycopy(buffer, contentOffset, v, 0, contentLength);
return v;
}
}