You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2013/04/26 00:55:32 UTC
svn commit: r1476001 - in /directory/shared/trunk/asn1/ber/src:
main/java/org/apache/directory/api/asn1/ber/tlv/IntegerDecoder.java
test/java/org/apache/directory/api/asn1/ber/tlv/PrimitivesTest.java
Author: elecharny
Date: Thu Apr 25 22:55:31 2013
New Revision: 1476001
URL: http://svn.apache.org/r1476001
Log:
Fixed the Integer BER decoding : when the value starts with 0x00, it may be a positive value with a high order bit set to 1
Modified:
directory/shared/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/IntegerDecoder.java
directory/shared/trunk/asn1/ber/src/test/java/org/apache/directory/api/asn1/ber/tlv/PrimitivesTest.java
Modified: directory/shared/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/IntegerDecoder.java
URL: http://svn.apache.org/viewvc/directory/shared/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/IntegerDecoder.java?rev=1476001&r1=1476000&r2=1476001&view=diff
==============================================================================
--- directory/shared/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/IntegerDecoder.java (original)
+++ directory/shared/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/IntegerDecoder.java Thu Apr 25 22:55:31 2013
@@ -72,11 +72,30 @@ public final class IntegerDecoder
{
return parseInt( value );
}
-
-
+
+
/**
* Helper method used to parse the integer. We don't check any minimal or maximal
* bound.
+ * An BER encoded int can be either positive or negative. It uses the minimum
+ * number of byts necessary to encode the value. The high order bit gives the
+ * sign of the integer : if it's 1, then it's a negative value, otherwise it's
+ * a positive value. Integer with a high order bit set to 1 but prefixed by a 0x00
+ * are positive. If the integer is negative, then the 2 complement value is
+ * stored<br/>
+ * Here are a few samples :
+ * <ul>
+ * <li>0x02 0x01 0x00 : integer 0</li>
+ * <li>0x02 0x01 0x01 : integer 1</li>
+ * <li>0x02 0x01 0x7F : integer 127</li>
+ * <li>0x02 0x01 0x80 : integer -128</li>
+ * <li>0x02 0x01 0x81 : integer -127</li>
+ * <li>0x02 0x01 0xFF : integer -1</li>
+ * <li>0x02 0x02 0x00 0x80 : integer 128</li>
+ * <li>0x02 0x02 0x00 0x81 : integer 129</li>
+ * <li>0x02 0x02 0x00 0xFF : integer 255</li>
+ * </ul>
+ * and so on...
*/
private static int parseInt( BerValue value ) throws IntegerDecoderException
{
@@ -89,21 +108,111 @@ public final class IntegerDecoder
throw new IntegerDecoderException( I18n.err( I18n.ERR_00036_0_BYTES_LONG_INTEGER ) );
}
- if ( bytes.length > 4 )
- {
- throw new IntegerDecoderException( I18n.err( I18n.ERR_00037_ABOVE_4_BYTES_INTEGER ) );
- }
+ boolean positive = true;
- for ( int i = 0; ( i < bytes.length ); i++ )
+ switch ( bytes.length )
{
- result = ( result << 8 ) | ( bytes[i] & 0x00FF );
+ case 5:
+ if ( bytes[0] == 0x00 )
+ {
+ if ( ( bytes[1] & ( byte ) 0x80 ) != ( byte ) 0x80 )
+ {
+ throw new IntegerDecoderException( I18n.err( I18n.ERR_00036_0_BYTES_LONG_INTEGER ) );
+ }
+
+ result = bytes[1] & 0x00FF;
+ result = ( result << 8 ) | ( bytes[2] & 0x00FF );
+ result = ( result << 8 ) | ( bytes[3] & 0x00FF );
+ result = ( result << 8 ) | ( bytes[4] & 0x00FF );
+ }
+ else
+ {
+ throw new IntegerDecoderException( I18n.err( I18n.ERR_00036_0_BYTES_LONG_INTEGER ) );
+ }
+
+ break;
+
+ case 4:
+ if ( bytes[0] == 0x00 )
+ {
+ result = bytes[1] & 0x00FF;
+ }
+ else
+ {
+ result = bytes[0] & 0x00FF;
+
+ if ( ( bytes[0] & ( byte ) 0x80 ) == ( byte ) 0x80 )
+ {
+ positive = false;
+ }
+
+ result = ( result << 8 ) | ( bytes[1] & 0x00FF );
+ }
+
+ result = ( result << 8 ) | ( bytes[2] & 0x00FF );
+ result = ( result << 8 ) | ( bytes[3] & 0x00FF );
+
+ break;
+
+ case 3:
+ if ( bytes[0] == 0x00 )
+ {
+ result = bytes[1] & 0x00FF;
+ }
+ else
+ {
+ result = bytes[0] & 0x00FF;
+
+ if ( ( bytes[0] & ( byte ) 0x80 ) == ( byte ) 0x80 )
+ {
+ positive = false;
+ }
+
+ result = ( result << 8 ) | ( bytes[1] & 0x00FF );
+ }
+
+ result = ( result << 8 ) | ( bytes[2] & 0x00FF );
+
+ break;
+
+ case 2:
+ if ( bytes[0] == 0x00 )
+ {
+ result = bytes[1] & 0x00FF;
+ }
+ else
+ {
+ result = bytes[0] & 0x00FF;
+
+ if ( ( bytes[0] & ( byte ) 0x80 ) == ( byte ) 0x80 )
+ {
+ positive = false;
+ }
+
+ result = ( result << 8 ) | ( bytes[1] & 0x00FF );
+ }
+
+ break;
+
+ case 1:
+ result = ( result << 8 ) | ( bytes[0] & 0x00FF );
+
+ if ( ( bytes[0] & ( byte ) 0x80 ) == ( byte ) 0x80 )
+ {
+ positive = false;
+ }
+
+ break;
+
+ default:
+ throw new IntegerDecoderException( I18n.err( I18n.ERR_00037_ABOVE_4_BYTES_INTEGER ) );
}
- if ( ( bytes[0] & 0x80 ) == 0x80 )
+ if ( !positive )
{
result = -( ( ( ~result ) + 1 ) & MASK[bytes.length - 1] );
}
-
+
return result;
}
}
Modified: directory/shared/trunk/asn1/ber/src/test/java/org/apache/directory/api/asn1/ber/tlv/PrimitivesTest.java
URL: http://svn.apache.org/viewvc/directory/shared/trunk/asn1/ber/src/test/java/org/apache/directory/api/asn1/ber/tlv/PrimitivesTest.java?rev=1476001&r1=1476000&r2=1476001&view=diff
==============================================================================
--- directory/shared/trunk/asn1/ber/src/test/java/org/apache/directory/api/asn1/ber/tlv/PrimitivesTest.java (original)
+++ directory/shared/trunk/asn1/ber/src/test/java/org/apache/directory/api/asn1/ber/tlv/PrimitivesTest.java Thu Apr 25 22:55:31 2013
@@ -21,10 +21,8 @@ package org.apache.directory.api.asn1.be
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
-import org.apache.directory.api.asn1.ber.tlv.BerValue;
-import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
-import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -69,6 +67,12 @@ public class PrimitivesTest
value.init( 2 );
value.setData( new byte[]
+ { ( byte ) 0x00, ( byte ) 0xFF } ); // res = 255
+ assertEquals( 255, IntegerDecoder.parse( value ) );
+ value.reset();
+
+ value.init( 2 );
+ value.setData( new byte[]
{ 0x00, 0x01 } ); // res = 1
assertEquals( 1, IntegerDecoder.parse( value ) );
value.reset();
@@ -97,31 +101,112 @@ public class PrimitivesTest
assertEquals( 512, IntegerDecoder.parse( value ) );
value.reset();
+ value.init( 2 );
+ value.setData( new byte[]
+ { 0x7F, ( byte ) 0xFF } ); // res = 32767
+ assertEquals( 32767, IntegerDecoder.parse( value ) );
+ value.reset();
+
+ value.init( 2 );
+ value.setData( new byte[]
+ { ( byte ) 0x80, 0x00 } ); // res = -32768
+ assertEquals( -32768, IntegerDecoder.parse( value ) );
+ value.reset();
+
+ value.init( 2 );
+ value.setData( new byte[]
+ { ( byte ) 0xFF, ( byte ) 0xFF } ); // res = -65535
+ assertEquals( -1, IntegerDecoder.parse( value ) );
+ value.reset();
+
value.init( 3 );
value.setData( new byte[]
{ 0x00, ( byte ) 0xFF, ( byte ) 0xFF } ); // res = 65535
assertEquals( 65535, IntegerDecoder.parse( value ) );
value.reset();
+ value.init( 3 );
+ // res = 65536
+ value.setData( new byte[]
+ { 0x01, 0x00, 0x00 } );
+ assertEquals( 65536, IntegerDecoder.parse( value ) );
+ value.reset();
+
+ value.init( 3 );
+ // res = 8388607
+ value.setData( new byte[]
+ { 0x7F, ( byte ) 0xFF, ( byte ) 0xFF } );
+ assertEquals( 8388607, IntegerDecoder.parse( value ) );
+ value.reset();
+
+ value.init( 3 );
+ // res = -8388608
+ value.setData( new byte[]
+ { ( byte ) 0x80, ( byte ) 0x00, ( byte ) 0x00 } );
+ assertEquals( -8388608, IntegerDecoder.parse( value ) );
+ value.reset();
+
+ value.init( 3 );
+ // res = -1
+ value.setData( new byte[]
+ { ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF } );
+ assertEquals( -1, IntegerDecoder.parse( value ) );
+ value.reset();
+
+ value.init( 4 );
+ // res = 16777215
+ value.setData( new byte[]
+ { 0x00, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF } );
+ assertEquals( 16777215, IntegerDecoder.parse( value ) );
+ value.reset();
+
value.init( 4 );
+ // res = 2^31 - 1 = MaxInt
value.setData( new byte[]
- { ( byte ) 0x7F, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF } ); // res
- // =
- // 2^31
- // - 1
- // =
- // MaxInt
+ { ( byte ) 0x7F, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF } );
assertEquals( Integer.MAX_VALUE, IntegerDecoder.parse( value ) );
value.reset();
value.init( 4 );
+ // res = 2^31 = MinInt
+ value.setData( new byte[]
+ { ( byte ) 0x80, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00 } );
+ assertEquals( Integer.MIN_VALUE, IntegerDecoder.parse( value ) );
+ value.reset();
+
+ value.init( 4 );
+ // res = -1
value.setData( new byte[]
- { ( byte ) 0x80, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00 } ); // res
- // =
- // 2^31
- // =
- // MinInt
+ { ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF } );
+ assertEquals( -1, IntegerDecoder.parse( value ) );
+ value.reset();
+
+ value.init( 5 );
+ // res = 2^31 = MinInt
+ value.setData( new byte[]
+ { 0x00, ( byte ) 0x80, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00 } );
assertEquals( Integer.MIN_VALUE, IntegerDecoder.parse( value ) );
value.reset();
+
+ value.init( 5 );
+ // res = 2^31 = MinInt
+ value.setData( new byte[]
+ { 0x00, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF } );
+ assertEquals( -1, IntegerDecoder.parse( value ) );
+ value.reset();
+
+ try
+ {
+ value.init( 5 );
+ // res = 2^31 = MinInt
+ value.setData( new byte[]
+ { 0x00, ( byte ) 0x7F, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00 } ); // res
+ IntegerDecoder.parse( value );
+ fail();
+ }
+ catch ( IntegerDecoderException ide )
+ {
+ // Expected
+ }
}
} // end class TLVTagDecoderTest