@@ -198,70 +198,92 @@ public static void ExpectedTag_IgnoresConstructed(
198198 [ InlineData ( AsnEncodingRules . BER ) ]
199199 [ InlineData ( AsnEncodingRules . CER ) ]
200200 [ InlineData ( AsnEncodingRules . DER ) ]
201- public static void ReadVeryLongOid ( AsnEncodingRules ruleSet )
201+ public static void ReadMaximumArcOid ( AsnEncodingRules ruleSet )
202202 {
203- byte [ ] inputData = new byte [ 100000 ] ;
204- // 06 83 02 00 00 (OBJECT IDENTIFIER, 65536 bytes).
205- inputData [ 0 ] = 0x06 ;
206- inputData [ 1 ] = 0x83 ;
207- inputData [ 2 ] = 0x01 ;
208- inputData [ 3 ] = 0x00 ;
209- inputData [ 4 ] = 0x00 ;
210- // and the rest are all zero.
211-
212- // The first byte produces "0.0". Each of the remaining 65535 bytes produce
213- // another ".0".
214- const int ExpectedLength = 65536 * 2 + 1 ;
215- StringBuilder builder = new StringBuilder ( ExpectedLength ) ;
216- builder . Append ( '0' ) ;
217-
218- for ( int i = 0 ; i <= ushort . MaxValue ; i ++ )
203+ const int MaxArcs = 64 ;
204+ // MaxArcs content bytes (all 0x7F) (which includes one for failure), plus one for the tag
205+ // plus one for the encoded length.
206+ byte [ ] input = new byte [ MaxArcs + 2 ] ;
207+ input . AsSpan ( ) . Fill ( 0x7F ) ;
208+ input [ 0 ] = 0x06 ;
209+ // The first two arcs are encoded in the first sub-identifier, so MaxArcs - 1.
210+ input [ 1 ] = MaxArcs - 1 ;
211+
212+ string decoded = AsnDecoder . ReadObjectIdentifier ( input , ruleSet , out int consumed ) ;
213+ Assert . Equal ( input . Length - 1 , consumed ) ;
214+
215+ StringBuilder expected = new StringBuilder ( 4 * MaxArcs ) ;
216+ expected . Append ( "2.47" ) ;
217+
218+ for ( int i = 2 ; i < MaxArcs ; i ++ )
219219 {
220- builder . Append ( '.' ) ;
221- builder . Append ( 0 ) ;
220+ expected . Append ( ".127" ) ;
222221 }
223222
224- AsnReader reader = new AsnReader ( inputData , ruleSet ) ;
225- string oidString = reader . ReadObjectIdentifier ( ) ;
223+ Assert . Equal ( expected . ToString ( ) , decoded ) ;
226224
227- Assert . Equal ( ExpectedLength , oidString . Length ) ;
228- Assert . Equal ( builder . ToString ( ) , oidString ) ;
225+ input [ 1 ] = MaxArcs ;
226+ AsnContentException ex = Assert . Throws < AsnContentException > (
227+ ( ) => AsnDecoder . ReadObjectIdentifier ( input , ruleSet , out _ ) ) ;
228+ Assert . Contains ( "OID" , ex . Message ) ;
229229 }
230230
231231 [ Theory ]
232232 [ InlineData ( AsnEncodingRules . BER ) ]
233233 [ InlineData ( AsnEncodingRules . CER ) ]
234234 [ InlineData ( AsnEncodingRules . DER ) ]
235- public static void ReadVeryLongOidArc ( AsnEncodingRules ruleSet )
235+ public static void ReadMaximumInitialSubIdentifier ( AsnEncodingRules ruleSet )
236236 {
237- byte [ ] inputData = new byte [ 255 ] ;
238- // 06 81 93 (OBJECT IDENTIFIER, 147 bytes).
239- inputData [ 0 ] = 0x06 ;
240- inputData [ 1 ] = 0x81 ;
241- inputData [ 2 ] = 0x93 ;
242-
243- // With 147 bytes we get 147*7 = 1029 value bits.
244- // The smallest legal number to encode would have a top byte of 0x81,
245- // leaving 1022 bits remaining. If they're all zero then we have 2^1022.
246- //
247- // Since it's our first sub-identifier it's really encoding "2.(2^1022 - 80)".
248- inputData [ 3 ] = 0x81 ;
249- // Leave the last byte as 0.
250- new Span < byte > ( inputData , 4 , 145 ) . Fill ( 0x80 ) ;
251-
252- const string ExpectedOid =
253- "2." +
254- "449423283715578976932326297697256183404494244735576643183575" +
255- "202894331689513752407831771193306018840052800284699678483394" +
256- "146974422036041556232118576598685310944419733562163713190755" +
257- "549003115235298632707380212514422095376705856157203684782776" +
258- "352068092908376276711465745599868114846199290762088390824060" +
259- "56034224" ;
237+ // First sub-identifier is 2^128 - 1, second is 1
238+ byte [ ] valid =
239+ {
240+ 0x06 , 0x14 , 0x83 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF ,
241+ 0xFF , 0xFF , 0xFF , 0xFF , 0x7F , 0x01 ,
242+ } ;
260243
261- AsnReader reader = new AsnReader ( inputData , ruleSet ) ;
244+ // First sub-identifier is 2^128, second is 1
245+ byte [ ] invalid =
246+ {
247+ 0x06 , 0x14 , 0x84 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 ,
248+ 0x80 , 0x80 , 0x80 , 0x80 , 0x00 , 0x01 ,
249+ } ;
250+
251+ string oid = AsnDecoder . ReadObjectIdentifier ( valid , ruleSet , out int consumed ) ;
252+ Assert . Equal ( valid . Length , consumed ) ;
253+ Assert . Equal ( "2.340282366920938463463374607431768211375.1" , oid ) ;
254+
255+ AsnContentException ex = Assert . Throws < AsnContentException > (
256+ ( ) => AsnDecoder . ReadObjectIdentifier ( invalid , ruleSet , out _ ) ) ;
257+ Assert . Contains ( "OID" , ex . Message ) ;
258+ }
259+
260+ [ Theory ]
261+ [ InlineData ( AsnEncodingRules . BER ) ]
262+ [ InlineData ( AsnEncodingRules . CER ) ]
263+ [ InlineData ( AsnEncodingRules . DER ) ]
264+ public static void ReadMaximumNonInitialSubIdentifier ( AsnEncodingRules ruleSet )
265+ {
266+ // First sub-identifier is 1, second is 2^128 - 1
267+ byte [ ] valid =
268+ {
269+ 0x06 , 0x14 , 0x01 , 0x83 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF ,
270+ 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0x7F ,
271+ } ;
272+
273+ // First sub-identifier is 1, second is 2^128
274+ byte [ ] invalid = new byte [ ]
275+ {
276+ 0x06 , 0x14 , 0x01 , 0x84 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 ,
277+ 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x00 ,
278+ } ;
279+
280+ string oid = AsnDecoder . ReadObjectIdentifier ( valid , ruleSet , out int consumed ) ;
281+ Assert . Equal ( valid . Length , consumed ) ;
282+ Assert . Equal ( "0.1.340282366920938463463374607431768211455" , oid ) ;
262283
263- string oidString = reader . ReadObjectIdentifier ( ) ;
264- Assert . Equal ( ExpectedOid , oidString ) ;
284+ AsnContentException ex = Assert . Throws < AsnContentException > (
285+ ( ) => AsnDecoder . ReadObjectIdentifier ( invalid , ruleSet , out _ ) ) ;
286+ Assert . Contains ( "OID" , ex . Message ) ;
265287 }
266288 }
267289}
0 commit comments