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