Class: Krypt::ASN1::Header

Inherits:
Object
  • Object
show all
Defined in:
ext/krypt/core/krypt_asn1_parser.c,
ext/krypt/core/krypt_asn1_parser.c

Overview

These are the tokens returned by Parser#next and cannot be instantiated on their own. A Header represents the Tag and Length part of a TLV (Tag-Length-Value) DER encoding, and it also allows to move the “cursor” on an IO forward by consuming or skipping the associated value (the V).

The Header itself contains tag and length information of what was just parsed:

  • tag number (Header#tag)

  • tag class (Header#tag_class)

  • whether the header is constructed or not (Header#constructed?)

  • whether it is an infinite length value or not (Header#infinite?)

  • the length in bytes of the associated value (Header#length/size)

  • the length of the raw Header encoding (Header#header_length/header_size)

In addition, there are three ways to consume the value that is associated with a Header:

  • by skipping it (Header#skip_value)

  • by reading the value in one single pass (Header#value)

  • or by obtaining an Instream of the value bytes so that it can be consumed in a streaming fashion (Header#value_io)

Access to the raw encoding of the Header is given by either retrieving a String containing the encoding with Header#bytes or by encoding it to an IO-like object supporting IO#write using Header#encode_to.

Instance Method Summary collapse

Instance Method Details

#bytesString

Returns a String containing the raw byte encoding of this Header.

Returns:

  • (String)


229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'ext/krypt/core/krypt_asn1_parser.c', line 229

static VALUE
krypt_asn1_header_bytes(VALUE self)
{
    krypt_asn1_parsed_header *header;
    uint8_t *bytes;
    size_t size;
    binyo_outstream *out;
    VALUE ret;

    int_asn1_parsed_header_get(self, header);

    out = binyo_outstream_new_bytes();
    if (krypt_asn1_header_encode(out, header->header) == KRYPT_ERR) {
	binyo_outstream_free(out);
	krypt_error_raise(eKryptASN1SerializeError, "Error while encoding ASN.1 header");
    }
    size = binyo_outstream_bytes_get_bytes_free(out, &bytes);
    ret = rb_str_new((const char *)bytes, size);
    rb_enc_associate(ret, rb_ascii8bit_encoding());
    xfree(bytes);
    return ret;
}

#constructed?Boolean

call-seq:

header.constructed? -> true or false

true if the current Header belongs to a constructed value, false otherwise.

Returns:

  • (Boolean)

#encode_toObject

#header_lengthObject Also known as: header_size

call-seq:

header.header_length -> Number

Returns the byte size of the raw header encoding. Never nil.

#infinite?Boolean

call-seq:

header.infinite? -> true or false

true if the current Header is encoded using infinite length, false otherwise. Note that an infinite length-encoded value is automatically constructed, i.e. header.constructed? => header.infinite?

Returns:

  • (Boolean)

#lengthObject Also known as: size

call-seq:

header.length -> Number

Returns a Number representing the raw byte length of the associated value. It is 0 is the Header represents an infinite length-encoded value. Never nil.

#skip_valuenil

Simply moves the “cursor” on the underlying IO forward by skipping over the bytes that represent the value associated with this Header. After having called skip_value, the next Header can be parsed from the underlying IO with Parser#next.

Returns:

  • (nil)


261
262
263
264
265
266
267
268
269
270
# File 'ext/krypt/core/krypt_asn1_parser.c', line 261

static VALUE
krypt_asn1_header_skip_value(VALUE self)
{
    krypt_asn1_parsed_header *header;
    
    int_asn1_parsed_header_get(self, header);
    if (krypt_asn1_skip_value(header->in, header->header) == KRYPT_ERR)
        krypt_error_raise(eKryptASN1ParseError, "Skipping the value failed");
    return Qnil;
}

#tagObject

call-seq:

header.tag -> Number

A Number representing the tag of this Header. Never nil.

#tag_classObject

call-seq:

header.tag_class -> Symbol

A Symbol representing the tag class of this Header. Never nil. See Krypt::ASN1::ASN1Data for possible values.

#to_sString

Prints out the information about this Header in a human-readable format without consuming (and therefore also not displaying) the associated value.

Returns:

  • (String)


376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
# File 'ext/krypt/core/krypt_asn1_parser.c', line 376

static VALUE
krypt_asn1_header_to_s(VALUE self)
{
    VALUE str;
    krypt_asn1_parsed_header *header;
    ID to_s;

    int_asn1_parsed_header_get(self, header);
    to_s = rb_intern("to_s");

    str = rb_str_new2("Tag: ");
    rb_str_append(str, rb_funcall(header->tag, to_s, 0));
    rb_str_append(str, rb_str_new2(" Tag Class: "));
    rb_str_append(str, rb_funcall(header->tag_class, to_s, 0));
    rb_str_append(str, rb_str_new2(" Length: "));
    rb_str_append(str, rb_funcall(header->length, to_s, 0));
    rb_str_append(str, rb_str_new2(" Header Length: "));
    rb_str_append(str, rb_funcall(header->header_length, to_s, 0));
    rb_str_append(str, rb_str_new2(" Constructed: "));
    rb_str_append(str, rb_funcall(header->constructed, to_s, 0));
    rb_str_append(str, rb_str_new2(" Infinite Length: "));
    rb_str_append(str, rb_funcall(header->infinite, to_s, 0));

    return str;
}

#valueString?

Returns the raw byte encoding of the associated value. Also moves the “cursor” on the underlying IO forward. After having called value, the next Header can be parsed from the underlying IO with Parser#next. Once read, the value will be cached and subsequent calls to #value will have no effect on the underlying stream.

If there is no value (indicated * by Header#length == 0), it returns nil.

May raise Krypt::ASN1::ParseError if an Instream was already obtained by Header#value_io, because the underlying stream can only be consumed once.

Returns:

  • (String, nil)


288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'ext/krypt/core/krypt_asn1_parser.c', line 288

static VALUE
krypt_asn1_header_value(VALUE self)
{
    krypt_asn1_parsed_header *header;
    
    int_asn1_parsed_header_get(self, header);

    if (header->consumed && header->cached_stream != Qnil)
	rb_raise(eKryptASN1ParseError, "The stream has already been consumed");

    /* TODO: sync */
    if (!header->consumed && header->value == Qnil) {
	uint8_t *value;
	size_t length;
	int tag;

	if (krypt_asn1_get_value(header->in, header->header, &value, &length) == KRYPT_ERR)
            rb_raise(eKryptASN1ParseError, "Parsing the value failed");
	tag = header->header->tag;

	if (length != 0 || (tag != TAGS_NULL && tag != TAGS_END_OF_CONTENTS)) {
	    header->value = rb_str_new((const char *)value, length);
	    rb_enc_associate(header->value, rb_ascii8bit_encoding());
	}

	header->consumed = 1;
	xfree(value);
    }

    return header->value;
}

#value_ioInstream

Returns a Krypt::ASN1::Instream that allows consuming the value in streaming manner rather than buffering it in a String and consuming it at once. Note that once an Instream was obtained in this way, all calls to Header#value will raise a ParseError. Subsequent calls to value_io are possible, however, the Instream instance is cached.

May raise Krypt::ASN1::ParseError if the associated value was already consumed by a call to Header#value.

Returns:



342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
# File 'ext/krypt/core/krypt_asn1_parser.c', line 342

static VALUE
krypt_asn1_header_value_io(int argc, VALUE *argv, VALUE self)
{
    krypt_asn1_parsed_header *header;
    VALUE values_only;

    rb_scan_args(argc, argv, "01", &values_only);
    
    int_asn1_parsed_header_get(self, header);
    if (header->consumed && header->cached_stream == Qnil)
	rb_raise(eKryptASN1ParseError, "The stream has already been consumed");

    /*TODO: synchronization */
    if (header->cached_stream == Qnil) {
	if (NIL_P(values_only))
	    values_only = Qtrue;

	header->consumed = 1;
	header->cached_stream = int_header_cache_stream(header->in,
	       			       	     	        header->header,
							values_only == Qtrue);
    }

    return header->cached_stream;
}