rasn1 0.16.1 → 0.16.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,7 +9,14 @@
9
9
  module RASN1
10
10
  module Types
11
11
  # ASN.1 Numeric String
12
+ #
13
+ # A NUMERIC STRING is an {OctetString} limited to numeric digit.
14
+ # @example Numeric string
15
+ # ns = RASN1::Types::NumrericString.new(value: "123")
16
+ # ns.to_der #=> "\x12\x03123"
17
+ # RASN1.parse(ns.to_der).value #=> "123"
12
18
  # @author Sylvain Daubert
19
+ # @author LemonTree55
13
20
  class NumericString < OctetString
14
21
  # NumericString id value
15
22
  ID = 18
@@ -23,10 +30,11 @@ module RASN1
23
30
  end
24
31
 
25
32
  # Make string value from +der+ string
26
- # @param [String] der
27
- # @param [::Boolean] ber
33
+ # @param der [String]
34
+ # @param ber [::Boolean]
28
35
  # @return [void]
29
36
  # @raise [ASN1Error] invalid characters detected
37
+ # @raise [ASN1Error] invalid character in string
30
38
  def der_to_value(der, ber: false)
31
39
  super
32
40
  check_characters
@@ -34,11 +42,15 @@ module RASN1
34
42
 
35
43
  private
36
44
 
45
+ # @return [String]
46
+ # @raise [ASN1Error] invalid character in string
37
47
  def value_to_der
38
48
  check_characters
39
49
  @value.to_s.b
40
50
  end
41
51
 
52
+ # @return [void]
53
+ # @raise [ASN1Error] invalid character in string
42
54
  def check_characters
43
55
  raise ASN1Error, "NUMERIC STRING #{@name}: invalid character: '#{$1}'" if @value.to_s =~ INVALID_CHARS
44
56
  end
@@ -9,6 +9,15 @@
9
9
  module RASN1
10
10
  module Types
11
11
  # ASN.1 Object ID
12
+ #
13
+ # An OBJECT ID provides unique identifiers.
14
+ #
15
+ # Object Id are shown as numbered dotted strings, like +0.1.2.1256.1+. First number is in range [0-2], the second
16
+ # in range [0-39]. Others are not limited.
17
+ #
18
+ # @example Object id
19
+ # oid = RASN1::Types::ObjectId.new(value: "0.2.145.65589.1")
20
+ # oid.to_der #=> "\x06\a\x02\x81\x11\x84\x805\x01"
12
21
  # @author Sylvain Daubert
13
22
  # @author LemonTree55
14
23
  class ObjectId < Primitive
@@ -16,8 +25,8 @@ module RASN1
16
25
  ID = 6
17
26
 
18
27
  # Make object id value from +der+ string
19
- # @param [String] der
20
- # @param [::Boolean] ber
28
+ # @param der [String]
29
+ # @param ber [::Boolean]
21
30
  # @return [void]
22
31
  def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
23
32
  bytes = der.unpack('C*')
@@ -41,6 +50,7 @@ module RASN1
41
50
 
42
51
  private
43
52
 
53
+ # @return [String]
44
54
  # @raise [ASN1Error]
45
55
  def value_to_der
46
56
  ids = @value.to_s.split('.').map(&:to_i)
@@ -59,8 +69,9 @@ module RASN1
59
69
  octets.pack('C*')
60
70
  end
61
71
 
62
- # @param [Array[::Integer]] ids
63
- # @raise [ASN1Error]
72
+ # @param ids [Array<::Integer>]
73
+ # @return [void]
74
+ # @raise [ASN1Error] one in two first ids are out of range
64
75
  def check_first_ids(ids)
65
76
  raise ASN1Error, "OBJECT ID #{@name}: first subidentifier should be less than 3" if ids[0] > 2
66
77
  raise ASN1Error, "OBJECT ID #{@name}: second subidentifier should be less than 40" if (ids[0] < 2) && (ids[1] > 39)
@@ -21,7 +21,7 @@ module RASN1
21
21
  # OctetString id value
22
22
  ID = 4
23
23
 
24
- # @param [::Integer] level
24
+ # @param level [::Integer]
25
25
  # @return [String]
26
26
  def inspect(level=0)
27
27
  str = common_inspect(level)
@@ -29,8 +29,8 @@ module RASN1
29
29
  end
30
30
 
31
31
  # Make string value from +der+ string. Force encoding to UTF-8
32
- # @param [String] der
33
- # @param [::Boolean] ber
32
+ # @param der [String]
33
+ # @param ber [::Boolean]
34
34
  # @return [void]
35
35
  # @since 0.15.0 Handle ENCODING constant, if defined by subclass
36
36
  def der_to_value(der, ber: false)
@@ -10,6 +10,10 @@ module RASN1
10
10
  module Types
11
11
  # @abstract This class SHOULD be used as base class for all ASN.1 primitive
12
12
  # types.
13
+ # This class is base class for all ASN.1 primitive types. A primitive type is not {Constructed}, or it cannot
14
+ # be broken down into more primitive types.
15
+ #
16
+ # Please note that a primitive type (b.e. {OctetString OCTET STRING}) may be set as constructed, to advertise it contains ASN.1 encoded data.
13
17
  # @author Sylvain Daubert
14
18
  class Primitive < Base
15
19
  # Primitive value
@@ -9,7 +9,10 @@
9
9
  module RASN1
10
10
  module Types
11
11
  # ASN.1 Printable String
12
+ #
13
+ # A PRINTABLE STRING is an {OctetString} limited to printable characters from ASCII table.
12
14
  # @author Sylvain Daubert
15
+ # @author LemonTree55
13
16
  class PrintableString < OctetString
14
17
  # PrintableString id value
15
18
  ID = 19
@@ -23,8 +26,8 @@ module RASN1
23
26
  end
24
27
 
25
28
  # Make string value from +der+ string
26
- # @param [String] der
27
- # @param [::Boolean] ber
29
+ # @param der [String]
30
+ # @param ber [::Boolean]
28
31
  # @return [void]
29
32
  # @raise [ASN1Error] invalid characters detected
30
33
  def der_to_value(der, ber: false)
@@ -34,11 +37,15 @@ module RASN1
34
37
 
35
38
  private
36
39
 
40
+ # @return [String]
41
+ # @raise [ASN1Error] invalid character in string
37
42
  def value_to_der
38
43
  check_characters
39
44
  @value.to_s.b
40
45
  end
41
46
 
47
+ # @return [void]
48
+ # @raise [ASN1Error] invalid character in string
42
49
  def check_characters
43
50
  m = @value.to_s.match(INVALID_CHARS)
44
51
  raise ASN1Error, "PRINTABLE STRING #{@name}: invalid character: '#{m[1]}'" if m
@@ -35,6 +35,7 @@ module RASN1
35
35
  # Sequence id value
36
36
  ID = 0x10
37
37
 
38
+ # @!macro type_initialize
38
39
  # @see Base#initialize
39
40
  def initialize(options={})
40
41
  super
@@ -59,7 +60,7 @@ module RASN1
59
60
  end
60
61
 
61
62
  # Get element at index +idx+, or element of name +name+
62
- # @param [Integer, String, Symbol] idx_or_name
63
+ # @param idx_or_name [Integer, String, Symbol]
63
64
  # @return [Object,nil]
64
65
  def [](idx_or_name)
65
66
  return unless @value.is_a?(Array)
@@ -73,8 +74,8 @@ module RASN1
73
74
  end
74
75
 
75
76
  # Make sequence value from +der+ string
76
- # @param [String] der
77
- # @param [::Boolean] ber
77
+ # @param der [String]
78
+ # @param ber [::Boolean]
78
79
  # @return [void]
79
80
  def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
80
81
  if @value.is_a?(Array) && !@value.empty?
@@ -90,6 +91,7 @@ module RASN1
90
91
 
91
92
  private
92
93
 
94
+ # @return [String]
93
95
  def value_to_der
94
96
  case @value
95
97
  when Array
@@ -99,10 +101,12 @@ module RASN1
99
101
  end
100
102
  end
101
103
 
104
+ # @return [String]
102
105
  def trace_data
103
106
  ''
104
107
  end
105
108
 
109
+ # @return [Sequence]
106
110
  def explicit_type
107
111
  self.class.new(name: name, value: @value)
108
112
  end
@@ -60,12 +60,13 @@ module RASN1
60
60
  attr_reader :of_type
61
61
 
62
62
  # A SEQUENCE OF is encoded as a SEQUENCE.
63
- # @return ['SEQUENCE']
63
+ # @return [String]
64
64
  def self.encoded_type
65
65
  Sequence.encoded_type
66
66
  end
67
67
 
68
- # @param [Class, Base] of_type base type for sequence of
68
+ # @param of_type [Class, Base] base type for sequence of
69
+ # @!macro type_initialize
69
70
  # @see Base#initialize
70
71
  def initialize(of_type, options={})
71
72
  super(options)
@@ -86,7 +87,9 @@ module RASN1
86
87
  end
87
88
 
88
89
  # Add an item to SEQUENCE OF
89
- # @param [Object] obj
90
+ # @param obj [Object]
91
+ # @return [self]
92
+ # @version 0.16.2 return self
90
93
  # @note
91
94
  # * if a SEQUENCE OF primitive type, +obj+ is an instance of primitive type or equivalent Ruby type
92
95
  # * if a SEQUENCE OF composed type, +obj+ is an array of ruby type instances
@@ -96,11 +99,12 @@ module RASN1
96
99
  return push_composed_array(obj) if composed_of_type?
97
100
 
98
101
  push_model(obj)
102
+ self
99
103
  end
100
104
 
101
105
  # Get element of index +idx+
102
- # @param [Integer] idx
103
- # @return [Base]
106
+ # @param idx [Integer]
107
+ # @return [Base,Wrapper,Model]
104
108
  def [](idx)
105
109
  @value[idx]
106
110
  end
@@ -111,7 +115,7 @@ module RASN1
111
115
  @value.length
112
116
  end
113
117
 
114
- # @param [::Integer] level
118
+ # @param level [::Integer]
115
119
  # @return [String]
116
120
  def inspect(level=0)
117
121
  str = common_inspect(level)
@@ -132,8 +136,8 @@ module RASN1
132
136
  end
133
137
 
134
138
  # Make sequence of value from +der+ string
135
- # @param [String] der
136
- # @param [::Boolean] ber
139
+ # @param der [String]
140
+ # @param ber [::Boolean]
137
141
  # @return [void]
138
142
  def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
139
143
  @value = []
@@ -148,22 +152,31 @@ module RASN1
148
152
 
149
153
  private
150
154
 
155
+ # Get class of elements
156
+ # @return [Class]
151
157
  def of_type_class
152
158
  @of_type.is_a?(Class) ? @of_type : @of_type.class
153
159
  end
154
160
 
161
+ # Is this SEQUENCE OF a composed one (i.e. of_type is a SET or a SEQUENCE)?
162
+ # @return [Boolean]
155
163
  def composed_of_type?
156
164
  !@of_type.is_a?(Class) && [Sequence, Set].include?(of_type_class)
157
165
  end
158
166
 
167
+ # @return [String]
159
168
  def value_to_der
160
169
  @value.map(&:to_der).join
161
170
  end
162
171
 
172
+ # @return [SequenceOf]
163
173
  def explicit_type
164
174
  self.class.new(self.of_type, name: name)
165
175
  end
166
176
 
177
+ # Push a primitice type into seld
178
+ # @param obj [Primitive]
179
+ # @return [void]
167
180
  def push_primitive(obj)
168
181
  @value <<
169
182
  case obj
@@ -174,6 +187,9 @@ module RASN1
174
187
  end
175
188
  end
176
189
 
190
+ # Push an array into a composed SEQUENCE OF
191
+ # @param obj [Array<Types::Base,Wrapper>]
192
+ # @return [void]
177
193
  def push_composed_array(obj)
178
194
  raise ASN1Error, 'object to add should be an Array' unless obj.is_a?(Array)
179
195
 
@@ -186,6 +202,9 @@ module RASN1
186
202
  @value << new_value
187
203
  end
188
204
 
205
+ # Push a model into self
206
+ # @param obj [Model]
207
+ # @return [void]
189
208
  def push_model(obj)
190
209
  case obj
191
210
  when Hash
@@ -197,6 +216,7 @@ module RASN1
197
216
  end
198
217
  end
199
218
 
219
+ # @return [String]
200
220
  def trace_data
201
221
  ''
202
222
  end
@@ -15,7 +15,7 @@ module RASN1
15
15
  ID = Set::ID
16
16
 
17
17
  # A SET OF is encoded as a SET.
18
- # @return ['SET']
18
+ # @return [String]
19
19
  def self.encoded_type
20
20
  Set.encoded_type
21
21
  end
@@ -14,6 +14,9 @@ module RASN1
14
14
  #
15
15
  # +{#value} of a +UtcTime+ should be a ruby Time.
16
16
  #
17
+ # Unlike {GeneralizedTime}, a UTCTime serializes only 2 digits for years.
18
+ # Unlike its name, a UTCTime may contain a local time.
19
+ #
17
20
  # ===Notes
18
21
  # When encoding, resulting string is always a UTC time, appended with +Z+.
19
22
  # Seconds are always generated.
@@ -34,8 +37,8 @@ module RASN1
34
37
  end
35
38
 
36
39
  # Make time value from +der+ string
37
- # @param [String] der
38
- # @param [::Boolean] ber
40
+ # @param der [String]
41
+ # @param ber [::Boolean]
39
42
  # @return [void]
40
43
  # @raise [ASN1Error] unrecognized time format
41
44
  def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
@@ -59,10 +62,12 @@ module RASN1
59
62
 
60
63
  private
61
64
 
65
+ # @return [String]
62
66
  def value_to_der
63
67
  @value.getutc.strftime('%y%m%d%H%M%SZ')
64
68
  end
65
69
 
70
+ # @return [String]
66
71
  def trace_data
67
72
  return super if explicit?
68
73
 
data/lib/rasn1/types.rb CHANGED
@@ -35,7 +35,7 @@ module RASN1
35
35
 
36
36
  # @private
37
37
  # Decode a DER string to extract identifier octets.
38
- # @param [String] der
38
+ # @param der [String]
39
39
  # @return [Array] Return ASN.1 class as Symbol, contructed/primitive as Symbol,
40
40
  # ID and size of identifier octets
41
41
  def self.decode_identifier_octets(der)
@@ -63,7 +63,7 @@ module RASN1
63
63
 
64
64
  # Give ASN.1 type from a DER string. If ID is unknown, return a {Types::Base}
65
65
  # object.
66
- # @param [String] der
66
+ # @param der [String]
67
67
  # @return [Types::Base]
68
68
  # @raise [ASN1Error] +tag+ is out of range
69
69
  def self.id2type(der)
@@ -93,9 +93,9 @@ module RASN1
93
93
 
94
94
  # Define a new ASN.1 type from a base one.
95
95
  # This new type may have a constraint defines on it.
96
- # @param [Symbol,String] name new type name. Must start with a capital letter.
97
- # @param [Types::Base] from class from which inherits
98
- # @param [Module] in_module module in which creates new type (default to {RASN1::Types})
96
+ # @param name [Symbol,String] new type name. Must start with a capital letter.
97
+ # @param from [Types::Base] class from which inherits
98
+ # @param in_module [Module] module in which creates new type (default to {RASN1::Types})
99
99
  # @return [Class] newly created class
100
100
  # @yieldparam [Object] value value to set to type, or infered at parsing
101
101
  # @yieldreturn [Boolean]
data/lib/rasn1/version.rb CHANGED
@@ -8,5 +8,5 @@
8
8
 
9
9
  module RASN1
10
10
  # RASN1 version number
11
- VERSION = '0.16.1'
11
+ VERSION = '0.16.3'
12
12
  end
data/lib/rasn1/wrapper.rb CHANGED
@@ -42,9 +42,13 @@ module RASN1
42
42
  class Wrapper < SimpleDelegator
43
43
  # @private Private class used to build/parse explicit wrappers
44
44
  class ExplicitWrapper < Types::Base
45
- ID = 0 # not used
46
- ASN1_PC = 0 # not constructed
45
+ # Explicit Wrapper ID (not used, but must be declared)
46
+ ID = 0
47
+ # PC bit: primitive
48
+ ASN1_PC = 0
47
49
 
50
+ # Blank type for explicit wrapper
51
+ # @return [String]
48
52
  def self.type
49
53
  ''
50
54
  end
@@ -60,17 +64,27 @@ module RASN1
60
64
 
61
65
  private
62
66
 
67
+ # @return [String]
63
68
  def value_to_der
64
69
  @value.is_a?(String) ? @value : @value.to_der
65
70
  end
66
71
 
72
+ # @return [String]
67
73
  def inspect_value
68
74
  ''
69
75
  end
70
76
  end
71
77
 
72
- # @param [Types::Base,Model] element element to wrap
73
- # @param [Hash] options
78
+ # @param element [Types::Base,Model] element to wrap
79
+ # @param options [Hash]
80
+ # @option options [Integer] :explicit Create an explicit wrapper with given ID
81
+ # @option options [Integer] :implicit Crerate an implicit wrapper woth given ID
82
+ # @option options [Integer] :default Default value (explicit wrapper only)
83
+ # @option options [Boolean] :optional Define wrapper (explicit one only) as optional
84
+ # @option options [Symbol] :class Wrapper ASN.1 class. Default to +:context+
85
+ # @option options [::Boolean] :constructed if +true+, set wrapper as constructed.
86
+ # @option options [::String] :name name for this wrapper
87
+ # @raise [RASN1::Error] +:implicit+ and +:explicit+ options are both provided
74
88
  def initialize(element, options={})
75
89
  @lazy = true
76
90
  opts = explicit_implicit(options)
@@ -119,8 +133,8 @@ module RASN1
119
133
  end
120
134
 
121
135
  # Parse a DER string. This method updates object.
122
- # @param [String] der DER string
123
- # @param [Boolean] ber if +true+, accept BER encoding
136
+ # @param der [String] DER string
137
+ # @param ber [Boolean] if +true+, accept BER encoding
124
138
  # @return [Integer] total number of parsed bytes
125
139
  # @raise [ASN1Error] error on parsing
126
140
  # @since 0.12.0
@@ -142,6 +156,7 @@ module RASN1
142
156
  end
143
157
 
144
158
  # @private
159
+ # @!macro do_parse
145
160
  # @see Types::Base#do_parse
146
161
  def do_parse(der, ber: false)
147
162
  if implicit?
@@ -207,8 +222,9 @@ module RASN1
207
222
  !constructed?
208
223
  end
209
224
 
210
- # @param [::Integer] level
225
+ # @param level [::Integer]
211
226
  # @return [String]
227
+ # @see Types::Base#inspect
212
228
  def inspect(level=0)
213
229
  return super() unless explicit?
214
230
 
@@ -217,6 +233,10 @@ module RASN1
217
233
 
218
234
  private
219
235
 
236
+ # @param options [Hash]
237
+ # @option options [Integer] :explicit
238
+ # @option options [Integer] :implicit
239
+ # @return [Hash] options with :explicit/:implicit keys deleted
220
240
  def explicit_implicit(options)
221
241
  opts = options.dup
222
242
  @explicit = opts.delete(:explicit)
@@ -224,12 +244,19 @@ module RASN1
224
244
  opts
225
245
  end
226
246
 
247
+ # @param options [Hash]
248
+ # @option options [Integer] :implicit
249
+ # @return [ExplicitWrapper]
227
250
  def generate_explicit_wrapper(options)
228
251
  # ExplicitWrapper is a hand-made explicit tag, but we have to use its implicit option
229
252
  # to force its tag value.
230
253
  @explicit_wrapper = ExplicitWrapper.new(options.merge(implicit: @explicit))
231
254
  end
232
255
 
256
+ # @param options [Hash]
257
+ # @option options [Integer] :default
258
+ # @option options [Boolean] :optional
259
+ # @return [Hash] hash with :default/:optional keys only
233
260
  def generate_explicit_wrapper_options(options)
234
261
  new_opts = {}
235
262
  new_opts[:default] = options[:default] if options.key?(:default)
@@ -237,6 +264,8 @@ module RASN1
237
264
  new_opts
238
265
  end
239
266
 
267
+ # @param from [Types::Base,nil]
268
+ # @return [Types::Base, Model]
240
269
  def generate_implicit_element(from=nil)
241
270
  el = (from || element).dup
242
271
  el.options = if element.explicit?
@@ -247,6 +276,8 @@ module RASN1
247
276
  el
248
277
  end
249
278
 
279
+ # @param register [Boolean]
280
+ # @return [Types::Base, Model]
250
281
  def lazy_generation(register: true)
251
282
  return __getobj__ unless @lazy
252
283
 
data/lib/rasn1.rb CHANGED
@@ -21,6 +21,7 @@ require_relative 'rasn1/types/visible_string'
21
21
  # @author LemonTree
22
22
  module RASN1
23
23
  # @private
24
+ # Container types
24
25
  CONTAINER_CLASSES = [Types::Sequence, Types::Set].freeze
25
26
 
26
27
  # Parse a DER/BER string without checking a model
@@ -30,9 +31,9 @@ module RASN1
30
31
  # ones use the same encoding as SEQUENCE and SET, respectively.
31
32
  # @note Real type of tagged value cannot be guessed. So, such tag will
32
33
  # generate {Types::Base} objects.
33
- # @param [String] der binary string to parse
34
- # @param [Boolean] ber if +true+, decode a BER string, else a DER one
35
- # @return [Types::Base, Array[Types::Base]]
34
+ # @param der [String] binary string to parse
35
+ # @param ber [Boolean] if +true+, decode a BER string, else a DER one
36
+ # @return [Types::Base, Array<Types::Base>]
36
37
  def self.parse(der, ber: false) # rubocop:disable Metrics/AbcSize
37
38
  result = []
38
39
  until der.nil? || der.empty?
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rasn1
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.1
4
+ version: 0.16.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - LemonTree55
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-08-13 00:00:00.000000000 Z
11
+ date: 2025-11-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: strptime
@@ -98,7 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
98
  - !ruby/object:Gem::Version
99
99
  version: '0'
100
100
  requirements: []
101
- rubygems_version: 3.3.15
101
+ rubygems_version: 3.2.33
102
102
  signing_key:
103
103
  specification_version: 4
104
104
  summary: Ruby ASN.1 library