Study about OID encoding and size limitations

This study contains some research about OID encodings, ASN.1, X.509 and security vulnerabilities as well as conformance and size limitation tests of software products inclusive bug reports.

by Daniel Marschall

Table of contents

1. BER encoding of OIDs
	1.1 Identifier octets
		1.1.1 Currently assigned tag numbers (Universal Class)
		1.1.2 Classes
	1.2 Length octets
	1.3 Content octets of OIDs
	1.4 Content octets of other types
2. OID Converter
3. Illegal OID encodings
	3.1 Length octet 0x00
	3.2 Length octet 0x80
	3.3 Length octet 0xFF
	3.4 Invalid type
	3.5 Illegal paddings
4. Software compatibility analysis for large OIDs
5. Bugs found by me
	5.1 [SOLVED] OpenSSL encodes a few OIDs wrong
	5.2.1 [Reported] OpenSSL displays root-arcs wrong
	5.2.2 [Reported] OpenSSL should accept standardized identifiers, like example
	5.3 [CRITICAL, Reported] Mac OS X cannot handle the OIDs 2.48+
	5.4 [SOLVED] OpenSSL crashes when limit of first subidentifier is reached
	5.5 [SOLVED] OpenSSL allows illegal paddings for first subidentifier
	5.6 [Reported] Apple allows illegal 0x80 padded OIDs
	5.7 [Not a bug] OpenSSL does not show errors on padded policy OIDs
	5.8 [Not yet reported] OpenSSL: Use Example OID
	5.9 [Not yet reported] OpenSSL cannot create 32768 bit RSA certificates
	5.10 [SOLVED] 0x80 padding bug in OID-Converter 1.6 - 1.9
	5.11 [SOLVED] BouncyCastle: Problems with ASN.1 Object Identifier parsing
	5.12 [Not yet reported] PolarSSL: DN does not show unknown OIDs correctly
6. Vulnerability: "NULL" inside CN security vulnerability
7. Vulnerability: Risks of overflowing OID identifiers in X.509 certificates
8. Limited RSA keysizes

1. BER encoding of OIDs

An OID is encoded in following BER format: "[identifier] [length] [content]" (TLV), described in Rec. ITU-T X.690.

There exists several formats like BER, CER or DER. DER is used for Rec. ITU-T X.509 certificates and requires always the shortest possible form of encodings, while BER also allows longer forms.

1.1 Identifier octets

      /+-------------- Class: 2 bit for Universal (00), Application (01), Context-specific (10) or Private (11)
      ||                      The class defines how the tag number is interpreted.
      ||                      Universal-0x06 is an absolute OID, Universal-0x0D is a relative OID.
      ||
      || /------------ P/C: 1 bit for primitive (0) or constructed (1). OIDs are always primitive (0)! (More information: See Rec. ITU-T X.609)
      || |
      vv v
0x06 (00 0 00110) = ABSOLUTE OID
0x0D (00 0 01101) = RELATIVE OID
           ^^^^^
           |||||
           \++++------- TAG NUMBER: 5 bit used for class (00110 = Absolute OID, 01101 = Relative OID)
                                    Possible values: 00000 (0) .. 11110 (30)
                                    Value 11111 means that a long-form of the class-tag is used (neccessary when encoding tag
                                    >= 31). The highest bit of the long-form octets is the "more" bit. (only last octet may have
                                    0 as highest bits). The remaining 7 bits are the bits which are concatenated
                                    (like the OID subidentifiers) The first octet may not be 0x80. (padding)
                                    BER: The long form may also be 0..30, so both, long-form and short-form are allowed.
                                    DER: Tags 0..30 MUST be encoded in short form and the long-form may only be used for tags >= 31.

Example:

xxx11111 1aaaaaaa 1bbbbbbb 0ccccccc

"11111" implies the long-form, which has in our example 3 octets.

The tag-number is then "000aaaaa aabbbbbb bccccccc"

Encoding is big endian.

Thanks to Jo Wilkes from metabit for providing some useful informations.

1.1.1 Known tag numbers (Universal Class)

Taken from Wikipedia. (Isn't there an official registry by ISO? More known tag numbers?)

EOC (End-of-Content)		P	0	0x00	xxx00000
BOOLEAN				P	1	0x01	xxx00001
INTEGER				P	2	0x02	xxx00010
BIT STRING			P/C	3	0x03	xxx00011
OCTET STRING			P/C	4	0x04	xxx00100
NULL				P	5	0x05	xxx00101
OBJECT IDENTIFIER		P	6	0x06	xxx00110
Object Descriptor		P	7	0x07	xxx00111
EXTERNAL			C	8	0x08	xxx01000
REAL (float)			P	9	0x09	xxx01001
ENUMERATED			P	10	0x0A	xxx01010
EMBEDDED PDV			C	11	0x0B	xxx01011
UTF8String			P/C	12	0x0C	xxx01100
RELATIVE-OID			P	13	0x0D	xxx01101
(reserved)           	    	-	14	0x0E	xxx01110
(reserved)			-	15	0x0F	xxx01111
SEQUENCE / SEQUENCE OF		C	16	0x10	xxx10000
SET / SET OF			C	17	0x11	xxx10001
NumericString			P/C	18	0x12	xxx10010
PrintableString			P/C	19	0x13	xxx10011
T61String (TeletexString)	P/C	20	0x14	xxx10100
VideotexString			P/C	21	0x15	xxx10101
IA5String			P/C	22	0x16	xxx10110
UTCTime				P/C	23	0x17	xxx10111
GeneralizedTime			P/C	24	0x18	xxx11000
GraphicString			P/C	25	0x19	xxx11001
VisibleString			P/C	26	0x1A	xxx11010
GeneralString			P/C	27	0x1B	xxx11011
UniversalString			P/C	28	0x1C	xxx11100
CHARACTER STRING		P/C	29	0x1D	xxx11101
BMPString			P/C	30	0x1E	xxx11110
*LONG FORM*			-	31	0x1F	xxx11111 [long form octets]

Currently, no tag number >= 31 for the Universal Class is known to me.

1.1.2 Classes

1.2 Length octets

- [length] is encoded as follows:
  0x00 .. 0x7F = The actual length is in this byte, followed by [data].
  0x80 + n     = The length of [data] is spread over the following 'n' bytes. (0 < n < 0x7F)
  0x80         = "indefinite length" (only constructed form) -- Invalid
  0xFF         = Reserved for further implementations -- Invalid
  See page 396 of ASN.1 - Communication between Heterogeneous Systems by Olivier Dubuisson.

1.3 Content octets of OIDs

- The top-level arcs were limited to 3 standard bodies "0" (iso), "1" (itu-t) and "2" (joint-iso-itu-t) in 1986 .
- It is NOT possible to encode any OID with root 3 or higher
- It is NOT possible to encode any root OID without any second element (e.g. "1")
- The OIDs { 0 0 } until { 0 39 } are encoding into 1 octet. ( "06 01 00" till "06 01 27" )
- It is NOT possible to encode { 0 x } with x >= 40
- The OIDs { 1 0 } until { 1 39 } are encoding into 1 octet. ( "06 01 28" till "06 01 4F" )
- It is NOT possible to encode { 1 x } with x >= 40
- The OIDs { 2 0 } until { 2 47 } are encoding into 1 octet. ( "06 01 50" till "06 01 7F" )
- It *IS* possible to encode { 2 x } with x >= 40
- It *IS* possible to encode { 2 x } with x >= 47
- The OIDs { 2 48 } till { 2 unlimited } encodes into 2 or more octets, while the highest is
  defined as "more" bit, like it is defined at the higher levels.
- Encoding is always big endian.
- Please note that you have to subtract 0x50 (80) from the second value, but not on any other value.
  Example: { 2 0 999 } is "06 03 50 87 67". { 2 0 } does encode into "50" and "999" got encoded to
  "87 67" at the third resp. any higher level. But: { 2 999 } is encoded into "06 02 88 37".
  "88 37" does encode into "999" at the second level and not to "1079". (Difference: 80)
- The encoding of the example OID { 2 999 } is "06 02 88 37".

1.4 Content octets of other types

Please see Rec. ITU-T X.690

2. OID Converter

The OID converter by Matthias Gärtner is not capable in UUIDs and has encoding problems with OIDs like 2.999 and cannot handle length greater than 0x7F (OpenSSL, Windows and Mozilla can handle them correctly)

I made great changes and have updated the program to version 1.10 which fixes:

Test it online: OID Converter (*)

(*) Please note bug #10 in version 1.6 till 1.9

3. Illegal OID encodings

Note: The following tests were done with Windows 7 and IE11 as well as Mozilla Firefox 31 Nightly.

3.1 Length octet 0x00

Length octet 0x00 used (OID cannot have zero length)

06 00 00
	Windows:       Whitespace shown
	Mozilla:       Certificate does not open
	OID Converter: Error message
	OpenSSL:       Error message
	Mac OS X:      Error message

3.2 Length octet 0x80

Length octet 0x80 used (indefinite length, only valid for constructed types)

06 80 00
	Windows:       Certificate incomplete
	Mozilla:       Certificate does not open
	OID Converter: Error message
	OpenSSL:       Error message
	Mac OS X:      Error message

3.3 Length octet 0xFF

Length octet 0xFF used (reserved for extensions)

06 FF 00
	Windows:       Certificate incomplete
	Mozilla:       Certificate does not open
	OID Converter: Error message
	OpenSSL:       Error message
	Mac OS X:      Error message

3.4 Invalid type

No valid OBJECT IDENTIFIER or RELATIVE-OID class tag used (e.g. type 0x08)

08 01 00
	Windows:       Certificate incomplete
	Mozilla:       Certificate does not open
	OID Converter: Error message
	OpenSSL:       Error message
	Mac OS X:      Error message

3.5 Illegal paddings

The subidentifier shall be encoded in the fewest possible octets, that is, the leading octet of the subidentifier shall not have the value 0x80. (See Rec. ITU-T X.690, clause 8.19.2)

The word "shall" shall be used to express mandatory requirements. The word "may" shall be used to express optional requirements. Although the negative form of "shall" is "shall not", the negative form of "may" is not "may not", but is "need not". The use of "may not" shall be avoided. (See Rec. ITU-T A.23, Annex A, clause 6.10.8 - Use of words)

06 07 01 80 80 80 80 80 7F (illegal_padding1.crt) - this *could* be decoded as 0.1.127
	Windows:       Whitespace
	Mozilla:       Outputs "(0 1 Unknown)"; also, the certificate chain will show the same cert (issued to itself) over and over, max. 20 times
	OID Converter: Error
	OpenSSL:       Error for EKU/DN-OIDs resp. hex-dump-fallback for OIDs in extensions (e.g. policy OIDs)
	Mac OS X:      0.1.127 (see bug #6)

06 02 80 01 (illegal_padding2.crt) - this *could* be decoded as 2.-79
	Windows:       Whitespace
	Mozilla:       Outputs "(Unknown)"; also, the certificate chain will show the same cert (issued to itself) over and over, max. 20 times
	OID Converter: Error
	OpenSSL:       Since July, 14th 2011: Error message
	               Older versions: 0.1 (see bug #5)
	Mac OS X:      2.48.1 (see bug #6)

06 02 80 7F (illegal_padding3.crt) - this *could* be decoded as 2.47
	Windows:       Whitespace
	Mozilla:       Outputs "(Unknown)"; also, the certificate chain will show the same cert (issued to itself) over and over, max. 20 times
	OID Converter: Error
	OpenSSL:       Since July, 14th 2011: Error message
	               Older versions: 2.47 (see bug #5)
	Mac OS X:      2.48.127 (see bug #6)

Since Apple does not show unknown OIDs in the subject/issuer's DN, the following test certificate contains policy OIDs which are visible (scroll down at the certificate viewer!)

Warning: As these Rec. ITU-T X.509 certificates contain very unusual values, your software might crash. I am not responsible for any damages. Use at your own risk!

4. Software compatibility analysis for large OIDs

The OID standards have no limit whatsoever about the depth of an OID in the OID tree (i.e., number of arcs) and the size of the integer associated to each OID arc. However, some tools may have size limitations.

Possible limits could be...

  1. Limitation of an arc size, e.g. 2.999.18446744073709551615
  2. Limitation of the total size of the dot-notation of an OID (string length)
  3. Limitation of the depth of a OID
  4. Limitation of the value of an attribute inside a Rec. ITU-T X.509 certificate
  5. Limitation of the length of the DER encoded data

I have created a Rec. ITU-T X.509 test certificate which contains large OID values (#1) as well as long OID strings (#2) to check which clients have limits. Here is the result of my study:

Product Biggest possible 1st subidentifier (2.[value]) Biggest possible higher level arc-value (e.g. 2.999.[value]) Display/Length/Depth limit UUID-Capable (128 bit)
Mozilla Firefox 4, 5 (x86)
Mozilla Thunderbird 3.1.10, 5.0 (x86)
Max 2.4294967215 (decoded 232-1), otherwise it is displayed as "(Unknown)" Max 4294967295 (232-1), otherwise the arc is shown as "Unknown", e.g. 2.999.4294967296.0 becomes "(2 999 Unknown 0)" Display of dot-notation is limited to 299 chars, the rest is cut off. No!
Windows XP, 7 (x86)
Windows Server 2008-R2 (x64)
Max 2.18446744073709551535 (decoded 264-1), otherwise, the whole OID is shown as whitespace Max 18446744073709551615 (264-1), otherwise, the whole OID is shown as whitespace Maximum 255 chars of dot-notation, otherwise whole OID is shown as whitespace. No!
OpenSSL 0.9.8o (1 Jun 2010) on Debian (x86) Since July, 14th 2011: Unlimited! (Creation/Reading)

Before: Bug #4 - Creation/Reading max: 2.2147483567 (decoded 232-1), otherwise AppCrash (Windows) or ErrorMessage (Linux).
Unlimited! The program will switch to BigNumber-library as soon as an arc is greater than 232-1 . Please note bug #1. Various: Display of dot-notation limited to 79 chars in EKUs or DNs, the rest is cut off. For OIDs inside X509v3 extensions (e.g. policy OIDs): Unlimited Yes!
OpenSSL 0.9.8k (25 Mar 2009) on Win2008 (x64) Since July, 14th 2011: Unlimited! (Creation/Reading)

Before: Bug #4 - Creation/Reading max: 2.18446744073709551535 (decoded 264-1), otherwise AppCrash (Windows) or ErrorMessage (Linux).
Unlimited! The program will switch to BigNumber-library as soon as an arc is greater than 264-1 . Please note bug #1. Various: *Display* limited to 79 chars in EKUs or DNs. For policy OIDs: Unlimited Yes!
OID-Converter 1.6 (x86) Unlimited! (GMP-Libary used) Unlimited! (GMP-Libary used) Unlimited! (GMP-Libary used) Yes!
Mac OS X 10.5.8 (32-Bit) Max 2.47 (decoded 27-1 = 127), then bug #3 will occur and the OIDs 2.48+ are wrongly decoded.

There is probably also an overflow possible. (ATTENTION, this is a security related issue)!
Max 2147483647 (232/2-1, signed int32 limit), then it begins at -2147483648 again (ATTENTION, this is a security related issue)! The DER encoding of an OID is limited to max 32 bytes (34 bytes inclusive content-octet and length-octet), otherwise the OID is marked as invalid.

As a result of this limitation: The max depth is 33 arcs if every arc's value is max 127 (0x7F) and the first 2 arcs are max 2.47 (decoded 0x7F). Or the biggest possible number is 0.0.210624583337114373395836055367340864637790190801098222508621955071 resp. 2.26959946667150639794667015087019630673637144422540572481103610249135 (but there will be integer-overflows as well as the bug #3).
No!
Mac OS X 10.6.6 (64-Bit)
MAC OS X Lion 10.7.4 (64-Bit)
Max 9223372036854775807 (264/2-1, signed int64 limit), then it begins at -9223372036854775808 again (ATTENTION, this is a security related issue)! No!
Microsoft MakeCert 5.131.1863.1 (x86) Max 2.18446744073709551535 (decoded 264-1), then it begins at 0.0 again (ATTENTION, this is a security related issue)! Max 18446744073709551615 (264-1), then it begins at 0 again (ATTENTION, this is a security related issue)! (No OID display) No!
BouncyCastle JAVA Unlimited! Unlimited! Unlimited! Yes!
Java's built-in OID class org.ietf.jgss.Oid Unlimited! Unlimited! Unlimited! (Display through .toString()) Yes!
ASN.1 JavaScript decoder by lapo.it Unlimited! Unlimited! Unlimited! (Output of very large/long OIDs may be trimmed to avoid horizontal scrolling) Yes!
OSS ASN-1Step Version 6.0.2.2 Max 2.18446744073709551535 (decoded 264-1), otherwise error messsages. For module identifying OIDs the limit is 32 bits and if the value goes above, the software will "truncate" the OID. Max 18446744073709551615 (264-1), otherwise error messsages. For module identifying OIDs the limit is 32 bits and if the value goes above, the software will "truncate" the OID. Display of OID limited to 32 characters (dots and numbers).

OID Depth limitaton when encoding into E-XER.
No!

Here is a screenshot of MAC OS X Lion 10.7.4, 64 bit

If you have more results, please send them to me: .

5. Bugs found by me

5.1 [SOLVED] OpenSSL encodes a few OIDs wrong

Please note that OpenSSL contained a bug (see report RT#2542 of June 19th 2011, login using guest/guest) in the encoding of OIDs.

The bug was fixed at June, 22th 2011 in the branches:

In x86-builds of OpenSSL, the faulty values were 4294967296..4294967299 (232 .. 232+3).

In x64-builds of OpenSSL, the faulty values were 18446744073709551616..18446744073709551619 (264 .. 264+3).

They were encoded into 0..3 instead of their real values. On Windows Server 2008 R2, the x64 bit version of OpenSSL also crashes as soon as the integer overflow happens.

5.2.1 [Reported] OpenSSL displays root-arcs wrong

OpenSSL display the following OIDs as:

0.0 = ITU-T
1.0 = ISO
2.0 = JOIUNT-ISO-ITU-T

This is wrong, for 2 reasons: (1) these identifiers need to be lowercase and (2) the description is only counting for the ROOT-arc (0, 1, 2) and not the root-arc, followed by the 2nd arc "0".

How to reproduce:

openssl req -nodes -newkey rsa:1024 -nodes -keyout mytest.key -out test.csr -subj "/CN=testcert/0.0=test0/1.0=Test1/2.0=test2"
openssl req -noout -text -in test.csr | grep "Subject:"

Actual behavior:

Subject: CN=testcert/0.0=test0/1.0=Test1/2.0=test2

Expected behavior:

Subject: CN=testcert/ITU-T=test0/ISO=Test1/JOINT-ISO-ITU-T=test2

See report: RT#2556 (part 1) of July 6th 2011, login using guest/guest

5.2.2 [Reported] OpenSSL should accept standardized identifiers, like example

Additional feature: Would be good to have 2.999 shown as "example".

See report: RT#2556 (part 1) of July 6th 2011, login using guest/guest

5.3 [CRITICAL, Reported] Mac OS X cannot handle the OIDs 2.48+

(This bug was reported via web contact form to Apple in June 2011. The mail was not answered and there was no fix.)

Mac OS X decodes OIDs which need more than one octet in the first two arcs wrong.

DER encoding "06 02 81 00" is shown as 2.49.0, but should be 2.48
DER encoding "06 02 81 01" is shown as 2.49.1, but should be 2.49
DER encoding "06 02 88 37" is shown as 2.56.55, but should be 2.999
and so on.

This violates Rec. ITU-T X.690, clause 8.19.4

This is also weird - I have no clue how they calculate THAT (Tested with a MAC OS X Lion 10.7.4, 64 bit):

2.4294967301 (DER = 06 05 90 80 80 80 55) is shown as "2.64.85"
2.18446744073709551621 (DER = 06 0A 82 80 80 80 80 80 80 80 80 55) is shown as "2.50.85"

The following screenshot shows the wrong decoding of OID arc 2.999:

Apple OIDs

The bug is still existing in OS X Yosemite 10.10.2 (64 bit).

Additional things:

- The usage of *signed* integer data types for an OID arc (which is always posive or zero) is very ... odd ... or let's say wrong.

- The size limitation of 34 bytes DER encoding per OID should be removed. There is no need to limit the DER encoding size.

- Minor priority: Apple should support UUID OIDs by using a BigInteger library (e.g. BigNum).

5.4 [SOLVED] OpenSSL crashes when limit of first subidentifier is reached

While OpenSSL can handle unlimited arc sizes for higher arcs (e.g. 2.999.[value]), the size of the first two arcs is limited to the respective ULONG_MAX (232-1 resp. 264-1). E.g. for x86 builds the highest possible OID to encode is 2.2147483567 . If this value is increased, Linux shows an non-informative error message and Windows reports an AppCrash. I would recommend also to use the combination between ULONG and BigNum like it is done for the higher arcs.

See report: RT#2556 (part 2) of July 6th 2011, login using guest/guest

The bug was fixed at July, 14th 2011 in the branches:

5.5 [SOLVED] OpenSSL allows illegal paddings for first subidentifier

The DER encoding "06 02 80 xx" which includes an illegal 0x80 padding at the first subidentifier can be decoded by OpenSSL, but is illegal as defined by Rec. ITU-T X.690, clause 8.19.2.

(by Steve) A bug in the check has another consequence: some correct OIDs like 2.65500 (06 03 84 80 2C) are rejected as having an invalid encoding.

The bug was fixed at July, 14th 2011 in the branches:

Note: For other subidentifiers, OpenSSL successfully marks the OIDs as invalid (e.g. "06 03 01 80 xx")

See report: RT#2556 (part 3) of July 6th 2011, login using guest/guest

5.6 [Reported] Apple allows illegal 0x80 padded OIDs

Their software decodes illegal padded 0x80 OIDs.

06 07 01 80 80 80 80 80 7F = Mac OS X says this is 0.1.127
06 02 80 01 = Mac OS X says this is 2.48.1
06 02 80 7F = Mac OS X says this is 2.48.127

This violates Rec. ITU-T X.690, clause 8.19.2.

Screenshot:

Apple OIDs 2

5.7 [Not a bug] OpenSSL does not show errors on padded policy OIDs

As reported in bug #5 ("OpenSSL allows illegal paddings for first subidentifier"), OpenSSL does allow the decoding of illegal 0x80 paddings in the first subidentifier.

For other subidentifiers, OpenSSL usually outputs an error message, as there is a check for sanity. But this check is not done on OIDs like policy OIDs in the text dump!

If a 0x80 padded OID occurs in the 2+ subidentifier, the whole policy section will be damaged and a hex-dump of the ASN.1 DER encoding will be shown in the textdump.

The MAC test certificate contains the following X509v3 Certificate Policies:
	1.2.3.4.5.6.7.8, DER[06 07 01 80 80 80 80 80 7F], DER[06 02 80 01], DER[06 02 80 7F], 1.2.3, 1.2.3

In the textdump this entry becomes:
	0.0...*......0..........0.....0.....0...*.0...*.

I have found out that here, a HEX-DUMP of a part of the certificate is outputted!

Content of DER cert (1) against output (2):
(1)	0.0...*......0....€€€€€.0...€.0...€.0...*.0...*.0...*†H†÷
(2)	0.0...*......0..........0.....0.....0...*.0...*.

To be sure that only the first illegal padded OID procudes this damage, I have also checked following:
	1.2.3.4.5.6.7.8, DER[06 07 01 00 00 00 00 00 7F], DER[06 02 80 01], DER[06 02 80 7F], 1.2.3, 1.2.3

And this gave the textdump
            X509v3 Certificate Policies:
                Policy: 1.2.3.4.5.6.7.8
                Policy: 0.1.0.0.0.0.0.127
                Policy: 0.1
                Policy: 2.47
                Policy: 1.2.3
                Policy: 1.2.3

Which is OK, but still has bug #5 for policies 0.1 and 2.47.

See report: RT#2556 (post 2) of July 13th 2011, login using guest/guest

Update: Since the fix of bug #5 in 2011-07-14, all 3 paddings lead to an hex-dump.

Update: The hex-dump is an expected behavior in X509v3 extensions.

5.8 [Not yet reported] OpenSSL: Use Example OID

In /etc/ssl/openssl.cnf (Debian Squeeze) there is following example code:

[ new_oids ]

# We can add new OIDs in here for use by 'ca' and 'req'.
# Add a simple OID like this:
# testoid1=1.2.3.4
# Or use config file substitution like this:
# testoid2=${testoid1}.5.6

It should be changed to testoid=2.999 . The OID 2.999 was allocated by ITU-T and ISO for this purpose. The "usage" (even for just documentation and/or examples) of the OID 1.2.3.4 is highly discouraged!

5.9 [Not yet reported] OpenSSL cannot create 32768 bit RSA certificates

please see here

5.10 [SOLVED] 0x80 padding bug in OID-Converter 1.6 - 1.9

My C and JAVA implementation of "OID converter" (see above) has a bug in the decoding routine of the versions 1.6 - 1.9.

The OID 2.99999999999999999 is correctly encoded to "06 09 81 B1 D1 AF 85 EC A8 80 4F".

But the decoding of "06 09 81 B1 D1 AF 85 EC A8 80 4F" back to 2.99999999999999999 is currently not possible. The error message "Encoding error. Illegal 0x80 paddings. (See Rec. ITU-T X.690, clause 8.19.2)" will appear (which is false).

Reason: The decoding routine checks if there are 0x80 paddings in front of each arc, which would be against the ITU-T recommendations. But the program did actually not recognize that the 0x80 is INSIDE the arc and not at its beginning: "06 09 81 B1 D1 AF 85 EC A8 80 4F".

The bug was fixed in the version 1.10

5.11 [SOLVED] BouncyCastle: Problems with ASN.1 Object Identifier parsing

See BouncyCastle bug tracker

5.12 [Not yet reported] PolarSSL: DN does not show unknown OIDs correctly

In the OpenVPN log file of a customer's iPhone I found following output:
2014-01-30 08:25:06 VERIFY OK: depth=0
cert. version : 3
serial number : 01
issuer name : C=DE, ST=BW, L=Heidelberg, O=FooBar, OU=myCA, CN=example.com, 0x29=myopenvpn, emailAddress=info@example.com
subject name : C=DE, ST=BW, L=Heidelberg, O=FooBar, OU=myCA, CN=server, 0x29=myopenvpn, emailAddress=info@example.com
issued on : 2014-01-29 09:25:59
expires on : 2024-01-27 09:25:59
signed using : RSA+SHA1
RSA key size : 1024 bits

Please note the 0x29=myopenvpn . Actually it should mean 2.5.4.41=myopenvpn or name=myopenvpn.

It turned out that it is a cosmetic bug in PolarSSL. It affects forks like TropicSSL, too. Also it affects OpenVPN for iPhone and Android because they wrap PolarSSL.

Actual behavior:

If the attribute OID is not inside 2.5.4 (ds) or 1.2.840.113549.1.9 (pkcs-9), it will be displayed as 0x(id)=(value) where (id) is the hexadecimal notation of the 5th resp. 10th octet of the DER encoding (which is NOT equal to the last arc if its value is greater than 0x7F). No system administratior or developer knows what 0x29 means!

If the OID is not inside ds or pkcs-9, then it will be displayed as ??=(value).

Expected behavior:

The attribute OID should ALWAYS be displayed completely, regardless of its parent arcs. The notation should be either dot-notation as defined per IETF RFC 2252 or ASN.1 notation as defined per ITU Rec. X.680 .

Affected products:

Why the hell can't they simply implement a printable_oid() function?

6. Vulnerability: "NULL" inside CN security vulnerability

Another important security vulnerability shown by Dan Kaminsky at 26C3 - Black OPs of PKI is the "NULL inside CN vulnerability".

The ITU-T did not define the NULL character as a special character for terminating the String sequence. Therefore it is a valid part of a String.

An attacker who wants to fake the connection to e.g. "google.com" could simply create a CSR with following CN: "google.com[NULL].attacker.com".

In case that the CA is running a software which is ITU-T conform (i.e. not recognizing NULL as a termination symbol), the CA will see "google.com[NULL].attacker.com". It will then run a Domain Validation for "attacker.com" which will be successful if the attacker owns attacker.com. The certificate will then be issued.

If the browser is now checking the certificate, it will probably interprete "google.com[NULL].attacker.com" as "google.com", e.g. if it is developed in C++. Now, the certificate is useable for intercepting a "google.com" connection. The scary part of this is that the user has NO CHANCE in finding out if the certificate is valid or not by just viewing the certificate. If the user opens the certificate in his browser, the program WILL show "google.com" instead of "google.com[NULL].attacker.com".

PLEASE NOTE: Even if the program SHOWS "google.com" at the GUI it is no evidence that it is actually vulnerable against such an attack, since the GUI and the "backend" (which is doing the validation of the certificate) are two separate parts. It is possible that the GUI does not 'escape' the NULL character to something (e.g. \0) while the core of the browser/OS/whatever might do a full Memory-Comparsion (e.g. memcmp()) instead of a C-String-Comparsion (e.g. strcmp(), NULL-terminated)! However, a good browser/OS/whatever should also ignore the [NULL] character in the GUI by simply replacing it with nothing or escape it with \0 or [NULL] or the NULL-UNICODE-Symbol (␀), so that experienced users can see what is actually happening with their connection.

In future I want to create a small testing-page which shows if your browser is vulnerable or not. I will also publish some testing results.

7. Vulnerability: Risks of overflowing OID identifiers in X.509 certificates

Software which has integer overflows (e.g. Microsoft MakeCert or MAC OS X) is probably vulnerable to allow false SSL certificates.

As shown by Dan Kaminsky at 26C3 - Black OPs of PKI, this can be used to incercept a secure communication.

A hacker can generate a CSR which contains following values:

2.5.4.3 (CN)               = badguy.example.com   (this is the "real" attribute which will be Domain-Verified (DV) by the CA)
2.5.4.4294967299           = google.com           (32 bit overflow attack, e.g. Apple x86)
2.5.4.18446744073709551619 = google.com           (64 bit overflow attack, e.g. MakeCert and Apple x64)

The attacker just need to find a CA which accepts CSR files without stroking unknown attributes like e.g. 2.5.4.4294967299 and which is using a non-overflowing OID implemention (e.g. OpenSSL). The CA will check the value 2.5.4.3 (CN) and will verify that badguy.example.com is owned by the person who is requesting the certificate. This will succeed and the hacker will get a valid X.509 certificate.

But the value 2.5.4.4294967299 will overflow to 2.5.4.3 for all 32 bit browsers with the overflow vulnerability and so the browser will interpret 2.5.4.4294967299 as 2.5.4.3 which is CN with the value google.com .

So we urge the vendors Microsoft and Apple to fix those bugs. Either they should implement a BigInteger solution or they should mark the OID as invalid as soon as the browser detects an integer overflow .

Of course you can also let the arc OID "2.5.4" (attributeType) or the root-arc 2.5 ("directory"), combinations of them or all together, overflow, e.g.:

2.5.4.3 (CN)                                  = badguy.example.com    (this is the "real" attribute which will be verified (DV) by the CA)

2.5.4.4294967299                              = google.com    (32 bit overflow of arc #2:   2.5.4.4294967299 = 2.5.4.3)
2.5.4294967300.3                              = google.com    (32 bit overflow of arc #1:     2.5.4294967300 = 2.5.4)
2.4294967301.4.3                              = google.com    (32 bit overflow of the root arc: 2.4294967301 = 2.5)
2.4294967301.4294967300.4294967299            = google.com    (32 bit overflow, everthing together)

2.5.4.18446744073709551619                    = google.com    (64 bit overflow of arc #2:   2.5.4.18446744073709551619 = 2.5.4.3)
2.5.18446744073709551620.3                    = google.com    (64 bit overflow of arc #1:     2.5.18446744073709551620 = 2.5.4)
2.18446744073709551621.4.3                    = google.com    (64 bit overflow of the root arc: 2.18446744073709551621 = 2.5)
2.18446744073709551621.18446744073709551620.18446744073709551619 = google.com (64 bit overflow, everthing together)

I have not yet checked if the vulnerability can actually be used, but you can download test certificates here.

Update for MAC OS X

I have checked it with MAC OS X Lion 10.7.4 (64 bit) and indeed the OIDs 2.5.4.3 did overflow. BUT the software seems to be NOT vulnerable. The OID 2.5.4.18446744073709551619 is shown as 2.5.4.3 in the (e.g. purposes), but the OID is shown as "Other name" not as "Common Name" in the attributes. So Apple probably checks the DER encoding matching to CN rather than checking the decoded OID value matching against 2.5.4.3.

But note that I have not yet checked if the "root arc" can be manipulated so that it shows 2.5.4 due to an overflow. And I do not know if THIS overflow is vulnerable or not.

8. Limited RSA keysizes

Note, that most programs cannot open 16.384 bit RSA keys.

The same goes to Convergence probably if you run a notary with a 16.384 bit key.

People, why don't you like 16.384 bit keys? You need to be prepared for DNA computers cracking your certs ;-)

Here is a bunch of test certificates you can use for testing!

The current analysis:

Further research needs to be done...


Last updated: 6 September 2017