@@ -495,16 +495,274 @@ def take_default_tag(klass)
495495 take_default_tag ( sklass )
496496 end
497497
498+ # :nodoc:
499+ TAG_CLASS_TYPES = {
500+ UNIVERSAL : 0x00 ,
501+ APPLICATION : 0x40 ,
502+ CONTEXT_SPECIFIC : 0x80 ,
503+ PRIVATE : 0xc0
504+ }
505+ private_constant :TAG_CLASS_TYPES
506+
498507 # from ossl_asn1.c : ossl_asn1_tag_class
499508 def take_asn1_tag_class ( tag_class )
500- case tag_class
501- when :UNIVERSAL , nil then 0x00
502- when :APPLICATION then 0x40
503- when :CONTEXT_SPECIFIC then 0x80
504- when :PRIVATE then 0xc0
505- else
509+ tag_class ||= :UNIVERSAL
510+
511+ TAG_CLASS_TYPES . fetch ( tag_class ) do
506512 raise ASN1Error , "invalid tag class"
507513 end
508514 end
515+
516+ PRIMITIVE_TAG_IDS = [ *( 0 ..10 ) , 12 , *( 18 ..28 ) , 30 ]
517+
518+ def decode_all ( data )
519+ data = data . to_der if data . respond_to? ( :to_der )
520+
521+ datalen = data . size
522+
523+ objs = [ ]
524+
525+ loop do
526+ obj , data = decode0 ( data )
527+
528+ if obj . nil?
529+ raise ASN1Error , "Type mismatch. Total bytes read: #{ datalen } Bytes available: #{ data . size } Offset: #{ datalen - data . size } "
530+ end
531+
532+ objs << obj
533+
534+ break if data . nil? || data . empty?
535+ end
536+
537+ objs
538+ end
539+
540+ def decode ( data )
541+ decode0 ( data ) . first
542+ end
543+
544+ def decode0 ( data )
545+ data = data . to_der if data . respond_to? ( :to_der )
546+
547+ first_byte , length = data . unpack ( 'CC' )
548+ length_bytes = 1
549+ tag_class = TAG_CLASS_TYPES . key ( first_byte & 0xc0 ) || :UNIVERSAL
550+ is_constructed = first_byte . anybits? ( 0x20 )
551+ is_indefinite_length = length == 0x80 # indefinite length
552+ id = first_byte & 0x1f
553+
554+ no_id_idx = if id == 0x1f
555+ id = 0
556+ count = 1
557+ data [ 1 ..] . each_byte do |byte |
558+ count += 1
559+
560+ id = ( id << 7 ) | ( byte & 0x7f )
561+ break if byte . nobits? ( 0x80 )
562+ end
563+ length = data . getbyte ( count )
564+ count
565+ else
566+ 1
567+ end
568+
569+ value = if is_indefinite_length
570+ unless is_constructed
571+ raise ASN1Error , "invalid length" if PRIMITIVE_TAG_IDS . include? ( id )
572+ end
573+
574+ data [ no_id_idx + 1 ..-1 ]
575+ elsif length > 0x80
576+ # ASN.1 says this octet can't be 0xff
577+ raise ASN1Error , "invalid length" if length == 0xff
578+ length_bytes = length & 0x7f
579+ length = data [ no_id_idx + 1 , length_bytes ] . unpack ( 'C*' ) . reduce ( 0 ) { |len , b | ( len << 8 ) | b }
580+ data [ no_id_idx + length_bytes + 1 ..-1 ]
581+ else
582+ data [ no_id_idx + 1 ..-1 ]
583+ end
584+
585+ if is_constructed
586+ decode_cons ( tag_class , id , length , value , is_indefinite_length )
587+ else
588+ if is_indefinite_length
589+ raise ASN1Error , "invalid length" if PRIMITIVE_TAG_IDS . include? ( id )
590+ end
591+ decode_prim ( tag_class , id , length , value )
592+ end
593+ end
594+
595+ def decode_cons ( tag_class , id , length , data , is_indefinite_length )
596+ remaining = data [ length ..-1 ]
597+ data = data [ 0 , length ]
598+
599+ objs = [ ]
600+ has_eoc = false
601+ until data . empty?
602+ obj , data = decode0 ( data )
603+
604+ case obj
605+ when EndOfContent
606+ has_eoc = true
607+
608+ break if is_indefinite_length
609+
610+ # next if is_indefinite_length
611+
612+ objs << obj
613+
614+ break
615+ else
616+ objs << obj
617+ end
618+ end
619+
620+ if is_indefinite_length && !has_eoc
621+ raise ASN1Error , "missing EOC"
622+ end
623+
624+ obj = if tag_class == :UNIVERSAL
625+ case id
626+ when 16 # Sequence
627+ Sequence . new ( objs , id , nil , tag_class )
628+ when 17 # Set
629+ Set . new ( objs , id , nil , tag_class )
630+ else
631+ Constructive . new ( objs , id , nil , tag_class )
632+ end
633+ else
634+ ASN1Data . new ( objs , id , tag_class )
635+ end
636+ obj . indefinite_length = is_indefinite_length
637+
638+ if data && !data . empty?
639+ if remaining . nil?
640+ remaining = data
641+ else
642+ remaining << data
643+ end
644+ end
645+
646+ return obj , remaining
647+ end
648+
649+ def decode_prim ( tag_class , id , length , data )
650+ remaining = data [ length ..-1 ]
651+ data = data [ 0 , length ]
652+
653+ obj = if tag_class == :UNIVERSAL
654+ case id
655+ when 0 # EOC
656+ if length != 0 || !data . empty?
657+ raise ASN1Error , "too long"
658+ end
659+ EndOfContent . new
660+ when 1 # BOOLEAN
661+ if length < 1
662+ raise ASN1Error , "invalid length for BOOLEAN"
663+ elsif length > 1
664+ raise ASN1Error , "too long"
665+ else
666+ Boolean . new ( data != "\x00 " , id , nil , tag_class )
667+ end
668+ when 2 # INTEGER
669+ number = data . unpack ( 'C*' ) . reduce ( 0 ) { |len , b | ( len << 8 ) | b }
670+ if data [ 0 ] . ord [ 7 ] == 1
671+ number -= ( 1 << ( 8 * length ) )
672+ end
673+ OpenSSL ::ASN1 ::Integer . new ( number . to_bn , id , nil , tag_class )
674+ when 3 # BIT_STRING
675+ if data . empty?
676+ raise ASN1Error , "string too short"
677+ end
678+ unused = data . unpack1 ( 'C' )
679+ if ( unused > 7 )
680+ raise ASN1Error , "invalid bit string bits left"
681+ end
682+ str = data . byteslice ( 1 ..-1 ) || ""
683+ BitString . new ( str , id , nil , tag_class ) . tap do |b |
684+ b . unused_bits = unused
685+ end
686+ when 4 # OCTET_STRING
687+ OctetString . new ( data , id , nil , tag_class )
688+ when 5 # NULL
689+ unless length . zero?
690+ raise ASN1Error , "null is wrong length"
691+ end
692+
693+ Null . new ( nil , id , nil , tag_class )
694+ when 6 # OBJECT
695+ top , *codes = data . unpack ( "w*" )
696+
697+ if top
698+ first = [ 2 , top / 40 ] . min
699+ second = top - first * 40
700+ codes = [ first , second , *codes ]
701+ else
702+ raise ASN1Error , "invalid object encoding"
703+ end
704+
705+ obj = ObjectId . new ( codes . join ( "." ) , id , nil , tag_class )
706+
707+ if ( sn = obj . sn )
708+ # on decoding, if there's a short name in the table, then
709+ # that's the value
710+ obj . value = sn
711+ end
712+ obj
713+ # when 7 # V_ASN1_OBJECT_DESCRIPTOR
714+ # when 8 # EXTERNAL
715+ # when 9 # REAL
716+ when 10 # ENUMERATED
717+ number = data . unpack ( 'C*' ) . reduce ( 0 ) { |len , b | ( len << 8 ) | b }
718+ if data [ 0 ] . ord [ 7 ] == 1
719+ number -= ( 1 << ( 8 * length ) )
720+ end
721+ OpenSSL ::ASN1 ::Enumerated . new ( number . to_bn , id , nil , tag_class )
722+ when 12 # UTF8String
723+ UTF8String . new ( data , id , nil , tag_class )
724+ when 18
725+ NumericString . new ( data , id , nil , tag_class )
726+ when 19
727+ PrintableString . new ( data , id , nil , tag_class )
728+ when 20
729+ T61String . new ( data , id , nil , tag_class )
730+ when 21
731+ VideotexString . new ( data , id , nil , tag_class )
732+ when 22
733+ IA5String . new ( data , id , nil , tag_class )
734+ when 23
735+ unless ( c = /\A (?<year>\d {2})(?<month>\d {2})(?<day>\d {2})(?<hour>\d {2})(?<min>\d {2})(?<sec>\d {2})Z\z / . match ( data ) )
736+ raise ASN1Error , "too long"
737+ end
738+ year = c [ :year ] . to_i
739+ year = year > 49 ? 1900 + year : 2000 + year
740+ time = Time . utc ( year , c [ :month ] , c [ :day ] , c [ :hour ] , c [ :min ] , c [ :sec ] )
741+ UTCTime . new ( time , id , nil , tag_class )
742+ when 24
743+ unless ( c = /\A (?<year>\d {4})(?<month>\d {2})(?<day>\d {2})(?<hour>\d {2})(?<min>\d {2})(?<sec>\d {2})Z\z / . match ( data ) )
744+ raise ASN1Error , "too long"
745+ end
746+ time = Time . utc ( c [ :year ] , c [ :month ] , c [ :day ] , c [ :hour ] , c [ :min ] , c [ :sec ] )
747+ GeneralizedTime . new ( time , id , nil , tag_class )
748+ when 25
749+ GraphicString . new ( data , id , nil , tag_class )
750+ when 26
751+ ISO64String . new ( data , id , nil , tag_class )
752+ when 27
753+ GeneralString . new ( data , id , nil , tag_class )
754+ when 28
755+ UniversalString . new ( data , id , nil , tag_class )
756+ when 30
757+ BMPString . new ( data , id , nil , tag_class )
758+ else
759+ ASN1Data . new ( data , id , tag_class )
760+ end
761+ else
762+ ASN1Data . new ( data , id , tag_class )
763+ end
764+
765+ return obj , remaining
766+ end
509767 end
510768end
0 commit comments