`oidToDer` wrote the first subidentifier (40 * arc1 + arc2) as a single
raw byte, and `derToOid` read it back as a single byte. Per X.690 8.19
the first subidentifier is a base-128 multi-byte value like every other
arc, so it can exceed one byte whenever arc1 is 2 (arc2 is then
unbounded). Both directions silently corrupted such OIDs:
oidToDer('2.999.3') // '43703' (should be '883703')
derToOid(hexToBytes('883703')) // '3.16.55.3' (should be '2.999.3')
This affects registered arcs that appear in real certificates, e.g.
2.41.x (biometrics), 2.49.x (NATO), 2.51.x (GS1).
Encode the first subidentifier through the existing base-128 loop, and
on decode accumulate it across continuation bytes before splitting it
into the first two arcs. Output verified against OpenSSL `asn1parse` and
the X.690 8.19 rule across an OID fuzz.
Problem
asn1.oidToDer / asn1.derToOid mis-handle the first OID subidentifier when it spans more than one byte. The first subidentifier encodes the first two arcs as 40 * arc1 + arc2; per X.690 §8.19 it is a base-128 multi-byte value like every other subidentifier, so for arc1 === 2 (where arc2 is unbounded) it routinely exceeds one byte. Both directions corrupt such OIDs:
This is not limited to the 2.999 example arc: registered arcs that appear in real certificates are affected, e.g. 2.41.x (biometrics, ISO/IEC JTC 1 SC 37), 2.49.x (NATO), 2.51.x (GS1). Any DER carrying such an OID is written wrong and read wrong.
Fix
Verification
The pre-existing >32-bit-arc limitation (the 0xffffffff guard / TODO) is unchanged and out of scope.