1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.api.asn1.ber;
21
22
23 import java.nio.ByteBuffer;
24
25 import org.apache.directory.api.asn1.DecoderException;
26 import org.apache.directory.api.asn1.ber.tlv.BerValue;
27 import org.apache.directory.api.asn1.ber.tlv.TLV;
28 import org.apache.directory.api.asn1.ber.tlv.TLVBerDecoderMBean;
29 import org.apache.directory.api.asn1.ber.tlv.TLVStateEnum;
30 import org.apache.directory.api.asn1.util.Asn1StringUtils;
31 import org.apache.directory.api.i18n.I18n;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35
36
37
38
39
40
41
42
43 public final class Asn1Decoder implements TLVBerDecoderMBean
44 {
45
46 private static final Logger LOG = LoggerFactory.getLogger( Asn1Decoder.class );
47
48
49 private static final boolean MORE = true;
50
51
52 private static final boolean END = false;
53
54
55 private boolean indefiniteLengthAllowed;
56
57
58 private int maxLengthLength;
59
60
61 private int maxTagLength;
62
63
64
65
66
67 private Asn1Decoder()
68 {
69 indefiniteLengthAllowed = false;
70 maxLengthLength = 1;
71 maxTagLength = 1;
72 }
73
74
75
76
77
78
79
80
81
82
83
84 private static boolean treatTagStartState( ByteBuffer stream, Asn1Container container )
85 {
86 if ( stream.hasRemaining() )
87 {
88 byte octet = stream.get();
89
90 TLV tlv = new TLV( container.getNewTlvId() );
91 tlv.setTag( octet );
92
93
94 container.setCurrentTLV( tlv );
95
96
97 tlv.setParent( container.getParentTLV() );
98
99
100 container.setState( TLVStateEnum.LENGTH_STATE_START );
101
102 if ( LOG.isDebugEnabled() )
103 {
104 byte tag = container.getCurrentTLV().getTag();
105 LOG.debug( I18n.msg( I18n.MSG_01000_TAG_DECODED, Asn1StringUtils.dumpByte( tag ) ) );
106 }
107
108 return MORE;
109 }
110 else
111 {
112
113 return END;
114 }
115 }
116
117
118
119
120
121
122
123 private static void dumpTLVTree( Asn1Container container )
124 {
125 StringBuilder sb = new StringBuilder();
126 TLV current = container.getCurrentTLV();
127
128 sb.append( "TLV" ).append( Asn1StringUtils.dumpByte( current.getTag() ) ).append( "(" ).append(
129 current.getExpectedLength() ).append( ")" );
130
131 current = current.getParent();
132
133 while ( current != null )
134 {
135 sb.append( "-TLV" ).append( Asn1StringUtils.dumpByte( current.getTag() ) ).append( "(" ).append(
136 current.getExpectedLength() ).append( ")" );
137 current = current.getParent();
138 }
139
140 if ( LOG.isDebugEnabled() )
141 {
142 LOG.debug( I18n.msg( I18n.MSG_01001_TLV_TREE, sb.toString() ) );
143 }
144 }
145
146
147
148
149
150
151
152
153 private static boolean isTLVDecoded( Asn1Container container )
154 {
155 TLV current = container.getCurrentTLV();
156 TLV parent = current.getParent();
157
158 while ( parent != null )
159 {
160 if ( parent.getExpectedLength() != 0 )
161 {
162 return false;
163 }
164
165 parent = parent.getParent();
166 }
167
168 BerValue value = current.getValue();
169
170 if ( ( value != null ) && ( value.getData() != null ) )
171 {
172 return current.getExpectedLength() == value.getData().length;
173 }
174 else
175 {
176 return current.getExpectedLength() == 0;
177 }
178 }
179
180
181
182
183
184
185
186
187
188
189
190
191
192 private static boolean treatLengthStartState( ByteBuffer stream, Asn1Container container ) throws DecoderException
193 {
194 if ( stream.hasRemaining() )
195 {
196 byte octet = stream.get();
197 TLV tlv = container.getCurrentTLV();
198
199 if ( ( octet & TLV.LENGTH_LONG_FORM ) == 0 )
200 {
201
202
203 tlv.setLength( octet );
204 tlv.setLengthNbBytes( 1 );
205
206 container.setState( TLVStateEnum.LENGTH_STATE_END );
207 }
208 else if ( ( octet & TLV.LENGTH_EXTENSION_RESERVED ) != TLV.LENGTH_EXTENSION_RESERVED )
209 {
210 int expectedLength = octet & TLV.LENGTH_SHORT_MASK;
211
212 if ( expectedLength > 4 )
213 {
214 String msg = I18n.err( I18n.ERR_01000_LENGTH_OVERFLOW );
215 LOG.error( msg );
216 throw new DecoderException( msg );
217 }
218
219 tlv.setLength( 0 );
220 tlv.setLengthNbBytes( 1 + expectedLength );
221 tlv.setLengthBytesRead( 1 );
222 container.setState( TLVStateEnum.LENGTH_STATE_PENDING );
223 }
224 else
225 {
226 String msg = I18n.err( I18n.ERR_01001_LENGTH_EXTENSION_RESERVED );
227 LOG.error( msg );
228 throw new DecoderException( msg );
229 }
230
231 return MORE;
232 }
233 else
234 {
235 return END;
236 }
237 }
238
239
240
241
242
243
244
245
246
247
248
249
250 private static boolean treatLengthPendingState( ByteBuffer stream, Asn1Container container )
251 {
252 if ( stream.hasRemaining() )
253 {
254 TLV tlv = container.getCurrentTLV();
255 int length = tlv.getLength();
256
257 while ( tlv.getLengthBytesRead() < tlv.getLengthNbBytes() )
258 {
259 byte octet = stream.get();
260
261 if ( LOG.isDebugEnabled() )
262 {
263 LOG.debug( I18n.msg( I18n.MSG_01002_CURRENT_BYTE, Asn1StringUtils.dumpByte( octet ) ) );
264 }
265
266 tlv.incLengthBytesRead();
267 length = ( length << 8 ) | ( octet & 0x00FF );
268
269 if ( !stream.hasRemaining() )
270 {
271 tlv.setLength( length );
272
273 if ( tlv.getLengthBytesRead() < tlv.getLengthNbBytes() )
274 {
275 container.setState( TLVStateEnum.LENGTH_STATE_PENDING );
276 return END;
277 }
278 else
279 {
280 container.setState( TLVStateEnum.LENGTH_STATE_END );
281 return MORE;
282 }
283 }
284 }
285
286 tlv.setLength( length );
287 container.setState( TLVStateEnum.LENGTH_STATE_END );
288
289 return MORE;
290 }
291 else
292 {
293
294 return END;
295 }
296 }
297
298
299
300
301
302
303
304
305 private static String getParentLength( TLV tlv )
306 {
307 StringBuilder buffer = new StringBuilder();
308
309 buffer.append( "TLV expected length stack : " );
310 TLV currentTlv = tlv;
311
312 while ( true )
313 {
314 if ( currentTlv == null )
315 {
316 buffer.append( " - null" );
317 break;
318 }
319 else
320 {
321 buffer.append( " - " ).append( currentTlv.getExpectedLength() );
322 }
323
324 currentTlv = currentTlv.getParent();
325 }
326
327 return buffer.toString();
328 }
329
330
331
332
333
334
335
336
337
338 private static void treatLengthEndState( Asn1Container container ) throws DecoderException
339 {
340 TLV tlv = container.getCurrentTLV();
341
342 if ( tlv == null )
343 {
344 String msg = I18n.err( I18n.ERR_01002_TLV_NULL );
345 LOG.error( msg );
346 throw new DecoderException( msg );
347 }
348
349 int length = tlv.getLength();
350
351
352
353
354 TLV parentTLV = container.getParentTLV();
355
356 if ( LOG.isDebugEnabled() )
357 {
358 LOG.debug( I18n.msg( I18n.MSG_01003_PARENT_LENGTH, getParentLength( parentTLV ) ) );
359 }
360
361 if ( parentTLV == null )
362 {
363
364
365 tlv.setExpectedLength( length );
366 container.setParentTLV( tlv );
367
368 if ( LOG.isDebugEnabled() )
369 {
370 LOG.debug( I18n.msg( I18n.MSG_01004_ROOT_TLV, Integer.valueOf( length ) ) );
371 }
372 }
373 else
374 {
375
376
377 int expectedLength = parentTLV.getExpectedLength();
378 int currentLength = tlv.getSize();
379
380 if ( expectedLength < currentLength )
381 {
382
383
384 if ( LOG.isDebugEnabled() )
385 {
386 LOG.debug( I18n.msg( I18n.MSG_01005_TLV,
387 Integer.valueOf( expectedLength ),
388 Integer.valueOf( currentLength ) ) );
389 }
390
391 throw new DecoderException( I18n.err( I18n.ERR_01003_VALUE_LENGTH_ABOVE_EXPECTED_LENGTH, Integer
392 .valueOf( currentLength ), Integer.valueOf( expectedLength ) ) );
393 }
394
395
396
397
398 if ( expectedLength == currentLength )
399 {
400 parentTLV.setExpectedLength( 0 );
401
402
403
404
405
406 if ( tlv.isConstructed() )
407 {
408
409
410
411 if ( length == 0 )
412 {
413
414
415
416 while ( parentTLV != null )
417 {
418 if ( parentTLV.getExpectedLength() != 0 )
419 {
420
421
422 break;
423 }
424 else
425 {
426 parentTLV = parentTLV.getParent();
427 }
428 }
429
430 container.setParentTLV( parentTLV );
431 }
432 else
433 {
434
435 container.setParentTLV( tlv );
436 }
437
438 tlv.setParent( parentTLV );
439 tlv.setExpectedLength( length );
440 }
441 else
442 {
443 tlv.setExpectedLength( length );
444
445
446
447
448 while ( parentTLV != null )
449 {
450 if ( parentTLV.getExpectedLength() != 0 )
451 {
452
453
454 break;
455 }
456 else
457 {
458 parentTLV = parentTLV.getParent();
459 }
460 }
461
462 container.setParentTLV( parentTLV );
463 }
464 }
465 else
466 {
467
468 parentTLV.setExpectedLength( expectedLength - currentLength );
469 tlv.setExpectedLength( length );
470
471 if ( tlv.isConstructed() )
472 {
473
474
475 tlv.setParent( parentTLV );
476 container.setParentTLV( tlv );
477 }
478 }
479
480 }
481
482 if ( LOG.isDebugEnabled() )
483 {
484 LOG.debug( I18n.msg( I18n.MSG_01006_LENGTH_DECODED, Integer.valueOf( length ) ) );
485 }
486
487 if ( length == 0 )
488 {
489
490 container.setState( TLVStateEnum.TLV_STATE_DONE );
491 }
492 else
493 {
494
495 container.setState( TLVStateEnum.VALUE_STATE_START );
496 }
497 }
498
499
500
501
502
503
504
505
506
507
508
509
510
511 private static boolean treatValueStartState( ByteBuffer stream, Asn1Container container )
512 {
513 TLV currentTlv = container.getCurrentTLV();
514
515 if ( TLV.isConstructed( currentTlv.getTag() ) && !container.isGathering() )
516 {
517 container.setState( TLVStateEnum.TLV_STATE_DONE );
518
519 return MORE;
520 }
521 else
522 {
523 int length = currentTlv.getLength();
524 int nbBytes = stream.remaining();
525
526 if ( nbBytes < length )
527 {
528 currentTlv.getValue().init( length );
529 currentTlv.getValue().setData( stream );
530 container.setState( TLVStateEnum.VALUE_STATE_PENDING );
531
532 return END;
533 }
534 else
535 {
536 currentTlv.getValue().init( length );
537 stream.get( currentTlv.getValue().getData(), 0, length );
538 container.setState( TLVStateEnum.TLV_STATE_DONE );
539
540 return MORE;
541 }
542 }
543 }
544
545
546
547
548
549
550
551
552
553
554
555
556 private static boolean treatValuePendingState( ByteBuffer stream, Asn1Container container )
557 {
558 TLV currentTlv = container.getCurrentTLV();
559
560 int length = currentTlv.getLength();
561 int currentLength = currentTlv.getValue().getCurrentLength();
562 int nbBytes = stream.remaining();
563
564 if ( ( currentLength + nbBytes ) < length )
565 {
566 currentTlv.getValue().addData( stream );
567 container.setState( TLVStateEnum.VALUE_STATE_PENDING );
568
569 return END;
570 }
571 else
572 {
573 int remaining = length - currentLength;
574 byte[] data = new byte[remaining];
575 stream.get( data, 0, remaining );
576 currentTlv.getValue().addData( data );
577 container.setState( TLVStateEnum.TLV_STATE_DONE );
578
579 return MORE;
580 }
581 }
582
583
584
585
586
587
588
589
590
591
592
593
594
595 @SuppressWarnings("unchecked")
596 private static boolean treatTLVDoneState( ByteBuffer stream, Asn1Container container ) throws DecoderException
597 {
598 if ( LOG.isDebugEnabled() )
599 {
600 dumpTLVTree( container );
601 }
602
603
604 container.getGrammar().executeAction( container );
605
606
607 if ( isTLVDecoded( container ) )
608 {
609 if ( container.getState() == TLVStateEnum.GRAMMAR_END )
610 {
611
612 container.setState( TLVStateEnum.PDU_DECODED );
613 }
614 else
615 {
616 if ( container.isGrammarEndAllowed() )
617 {
618
619 container.setState( TLVStateEnum.PDU_DECODED );
620 }
621 else
622 {
623 LOG.error( I18n.err( I18n.ERR_01004_MORE_TLV_EXPECTED ) );
624 throw new DecoderException( I18n.err( I18n.ERR_01005_TRUNCATED_PDU ) );
625 }
626 }
627 }
628 else
629 {
630
631 container.setState( TLVStateEnum.TAG_STATE_START );
632 }
633
634 return stream.hasRemaining();
635 }
636
637
638
639
640
641
642
643
644
645
646
647
648
649 public static void decode( ByteBuffer stream, Asn1Container container ) throws DecoderException
650 {
651
652
653
654
655
656
657
658
659
660
661 boolean hasRemaining = stream.hasRemaining();
662
663
664 container.incrementDecodedBytes( stream.remaining() );
665
666 if ( container.getDecodedBytes() > container.getMaxPDUSize() )
667 {
668 String message = I18n.err( I18n.ERR_01007_PDU_SIZE_TOO_LONG, container.getDecodedBytes(), container
669 .getMaxPDUSize() );
670 LOG.error( message );
671 throw new DecoderException( message );
672 }
673
674 if ( LOG.isDebugEnabled() )
675 {
676 LOG.debug( I18n.msg( I18n.MSG_01007_LINE_SEPARATOR1 ) );
677 LOG.debug( I18n.msg( I18n.MSG_01011_DECODING_PDU ) );
678 LOG.debug( I18n.msg( I18n.MSG_01008_LINE_SEPARATOR2 ) );
679 }
680
681 while ( hasRemaining )
682 {
683 if ( LOG.isDebugEnabled() )
684 {
685 LOG.debug( I18n.msg( I18n.MSG_01012_STATE, container.getState() ) );
686
687 if ( stream.hasRemaining() )
688 {
689 byte octet = stream.get( stream.position() );
690
691 LOG.debug( I18n.msg( I18n.MSG_01013_CURRENT_BYTE, Asn1StringUtils.dumpByte( octet ) ) );
692 }
693 else
694 {
695 LOG.debug( I18n.msg( I18n.MSG_01014_NO_MORE_BYTE ) );
696 }
697 }
698
699 switch ( container.getState() )
700 {
701 case TAG_STATE_START:
702
703 container.setGrammarEndAllowed( false );
704 hasRemaining = treatTagStartState( stream, container );
705
706 break;
707
708 case LENGTH_STATE_START:
709 hasRemaining = treatLengthStartState( stream, container );
710
711 break;
712
713 case LENGTH_STATE_PENDING:
714 hasRemaining = treatLengthPendingState( stream, container );
715
716 break;
717
718 case LENGTH_STATE_END:
719 treatLengthEndState( container );
720
721 break;
722
723 case VALUE_STATE_START:
724 hasRemaining = treatValueStartState( stream, container );
725
726 break;
727
728 case VALUE_STATE_PENDING:
729 hasRemaining = treatValuePendingState( stream, container );
730
731 break;
732
733 case VALUE_STATE_END:
734 hasRemaining = stream.hasRemaining();
735
736
737 break;
738
739 case TLV_STATE_DONE:
740 hasRemaining = treatTLVDoneState( stream, container );
741
742 break;
743
744 case PDU_DECODED:
745
746
747 if ( LOG.isDebugEnabled() )
748 {
749 LOG.debug( I18n.err( I18n.ERR_01008_REMAINING_BYTES_FOR_DECODED_PDU ) );
750 }
751
752 hasRemaining = false;
753
754 break;
755
756 default:
757 break;
758 }
759 }
760
761 if ( LOG.isDebugEnabled() )
762 {
763 LOG.debug( I18n.msg( I18n.MSG_01009_LINE_SEPARATOR3 ) );
764
765 if ( container.getState() == TLVStateEnum.PDU_DECODED )
766 {
767 if ( container.getCurrentTLV() != null )
768 {
769 LOG.debug( I18n.msg( I18n.MSG_01015_STOP_DECODING, container.getCurrentTLV().toString() ) );
770 }
771 else
772 {
773 LOG.debug( I18n.msg( I18n.MSG_01016_STOP_DECODING_NULL_TLV ) );
774 }
775 }
776 else
777 {
778 if ( container.getCurrentTLV() != null )
779 {
780 LOG.debug( I18n.msg( I18n.MSG_01017_END_DECODING, container.getCurrentTLV().toString() ) );
781 }
782 else
783 {
784 LOG.debug( I18n.msg( I18n.MSG_01018_END_DECODING_NULL_TLV ) );
785 }
786 }
787
788 LOG.debug( I18n.msg( I18n.MSG_01010_LINE_SEPARATOR4 ) );
789 }
790 }
791
792
793
794
795
796 @Override
797 public int getMaxLengthLength()
798 {
799 return maxLengthLength;
800 }
801
802
803
804
805
806 @Override
807 public int getMaxTagLength()
808 {
809 return maxTagLength;
810 }
811
812
813
814
815
816 @Override
817 public boolean isIndefiniteLengthAllowed()
818 {
819
820 return indefiniteLengthAllowed;
821 }
822 }