David 天宇 Wong
David 天宇 Wong

Reputation: 4197

How to modify a DER file

I have a .pem file I parsed thanks to openssl asn1parse.

Now I want to change some of the values, how to I make it back to a .pem file?

Upvotes: 1

Views: 2431

Answers (3)

jsantander
jsantander

Reputation: 5102

If using the "by hand" route, a few things to take into account:

  1. DER (and BER) encoding of ASN.1 use a Tag-Length-Value format. The Tag describes the item while the Lenght provides how long the value runs.
  2. The Tag whether the item is constructed (i.e. whether the value is another ASN.1). This is bit 6 of the first byte of the tag.
  3. The Tag is typically one byte but it could extend to multiple bytes if the tag value is greater than 30.
  4. The Length can be encoded in one or more bytes. If length is <= 127 (0x7f) it will only use one byte (note that bit 8 will be 0). If lenght is > 127 the first byte will have the bit 8 set and it will contain the number of bytes needed to represent the length.

Hand decoding

So for quick decoding use the following rules:

Find the tag. If the first byte is:

  • 0x[13579bdf]f. Then it is a multibyte tag. keep reading until you find a byte < 0x7f. That will be the last byte. Go to next byte
  • Other. Then it is single-byte tag. Go to next byte

Make note of the bit 6 of the first byte (i.e. 0x[2367abef] on the first nibble). This is the constructed bit.

Now for the length. If the first byte is:

  • byte > 0x7f: Then it is a multibyte length. The number of bytes to read afterwards is encoded in this first byte. Read the length
  • byte <= 0x7f: Then this is the length.

Now for the value. Read the number of bytes as indicated by the length.

Consider the constructed bit that we found on the tag to decide if you need to start the process over for the value bytes.

Keep doing this until you've run out of bytes.

Hand encoding

  • If you're modifying you will not need to worry about tags, all you need to worry is about values and lengths.

  • Modify the values to suit your needs.

  • Work upwards modifying the lengths of the enclosing types.

  • Pay attention to the 127 length limit. If one of your enclosing types exceeds it, replace it with 81 LL (where LL is your now 255 max length)... In this case remember that you have to account for increase in the number of bytes of the length encoding in the length of the enclosing types.

  • Similar things might happen if you jump over 255, 65535, 16777215, etc....lengths: Must increase the number of bytes to encode the length (0x82, 0x83...) and use them to encode the new length.

Example

I'll use this message.

62 6a 48 04 01 00 00 00 6b 1e 28 1c 06 07 00 11
86 05 01 01 01 a0 11 60 0f 80 02 07 80 a1 09 06
07 04 00 00 00 00 00 09 6c 42 a1 40 02 01 01 02
01 00 30 38 80 01 61 82 07 83 10 19 33 50 71 05
83 07 83 13 19 78 97 21 04 88 01 80 89 01 04 af
11 30 0f 02 01 21 a1 0a 80 08 13 12 f1 01 ab 01
5d 68 bb 05 80 03 80 90 a3 9c 01 0c

This is from a different application domain, unrelated to certificates, but I believe it can illustrate.

62 is a single byte tag ad 6a is a single byte length (106). Since I have 0x6 in the first nibble, I know it is a constructed type.

next is 48, this is single byte tag, the start of an ASN.1 type enclosed in the 62 one. I know it is not constructed. I can read its length 0x04 (single-byte length) and its value (4 more bytes: 0x01000000)

So I can go on....

62 6a 
   48 04 : 01 00 00 00 
   6b 1e
      28 1c 
         06 07 : 00 11 86 05 01 01 01 
         a0 11
            60 0f 
               80 02 : 07 80 
               a1 09 
                  06 07 04 00 00 00 00 00 09 
   6c 42 
      a1 40 
         02 01 : 01 
         02 01 : 00 
         30 38 
            80 01 : 61 
            82 07 : 83 10 19 33 50 71 05 
            83 07 : 83 13 19 78 97 21 04 
            88 01 : 80 
            89 01 : 04 
            af 11 
               30 0f 
                  02 01 : 21 
                  a1 0a 
                     80 08 : 13 12 f1 01 ab 01 5d 68 
            bb 05 
               80 03 : 80 90 a3 
            9c 01 : 0c

If I were to modify e.g. the first value (in the 0x48 tag) to be 0x1234567890

I could do so,

62 6a 
   48 04 : 01 00 00 00 

to be:

62 6a 
   48 04 : _12 34 56 78 90_ 

but now I need to increase the length:

62 6a 
   48 _05_ : 12 34 56 78 90 

and the length of the enclosing type:

62 _6b_ 
   48 05 : 12 34 56 78 90 

The new message is:

62 _6b_ 48 _05_ _12_ _34_ _56_ _78_ _90_ 
6b 1e 28 1c 06 07 00 11
86 05 01 01 01 a0 11 60 0f 80 02 07 80 a1 09 06
07 04 00 00 00 00 00 09 6c 42 a1 40 02 01 01 02
01 00 30 38 80 01 61 82 07 83 10 19 33 50 71 05
83 07 83 13 19 78 97 21 04 88 01 80 89 01 04 af
11 30 0f 02 01 21 a1 0a 80 08 13 12 f1 01 ab 01
5d 68 bb 05 80 03 80 90 a3 9c 01 0c

Upvotes: 3

David 天宇 Wong
David 天宇 Wong

Reputation: 4197

It's actually pretty easy to modify it by hand. Just open it, modify the value I want to modify and changes the "length" if the length has changed. It's the byte right before what I just changed.

DER works like this: TLV (tag, length, value)

example: 02 02 00 aa (02: integer, 02: size of payload, 00 aa payload (integer has to start with a 0 as first bit, otherwise it's a negative integer, so here we had to add one more byte to the payload)

also if your payload's length is more than 127bits, you have to write the size twice (at least that's my understanding).

If you change the length of some value, you have to change the global length in the header as well.

Upvotes: -1

ed_at_objsys
ed_at_objsys

Reputation: 1

It is not always easy modifying the value and changing the length. The content items are DER encoded so unless it is a text field, it takes a bit of know-how to get into binary form. And the lengths may be nested, so you may need to change lengths at different levels.

We have a tool that can do this available at http://www.obj-sys.com/products/asn1ve/index.php.

Upvotes: -1

Related Questions