/// <summary> /// Encode the segments { tag, length, value } of an object identifier (Oid). /// </summary> /// <returns>The encoded segments { tag, length, value }</returns> internal static byte[][] SegmentedEncodeOid(Oid oid) { Debug.Assert(oid != null); // All exceptions past this point should just be "CryptographicException", because that's // how they'd come back from Desktop/Windows, since it was a non-success result of calling // CryptEncodeObject. string oidValue = oid.Value; if (string.IsNullOrEmpty(oidValue)) throw new CryptographicException(SR.Argument_InvalidOidValue); if (oidValue.Length < 3 /* "1.1" is the shortest value */) throw new CryptographicException(SR.Argument_InvalidOidValue); if (oidValue[1] != '.') throw new CryptographicException(SR.Argument_InvalidOidValue); int firstRid; switch (oidValue[0]) { case '0': firstRid = 0; break; case '1': firstRid = 1; break; case '2': firstRid = 2; break; default: throw new CryptographicException(SR.Argument_InvalidOidValue); } int startPos = 2; // The first two RIDs are special: // ITU X.690 8.19.4: // The numerical value of the first subidentifier is derived from the values of the first two // object identifier components in the object identifier value being encoded, using the formula: // (X*40) + Y // where X is the value of the first object identifier component and Y is the value of the // second object identifier component. // NOTE – This packing of the first two object identifier components recognizes that only // three values are allocated from the root node, and at most 39 subsequent values from // nodes reached by X = 0 and X = 1. BigInteger rid = ParseOidRid(oidValue, ref startPos); rid += 40 * firstRid; // The worst case is "1.1.1.1.1", which takes 4 bytes (5 rids, with the first two condensed) // Longer numbers get smaller: "2.1.127" is only 2 bytes. (81d (0x51) and 127 (0x7F)) // So length / 2 should prevent any reallocations. List<byte> encodedBytes = new List<byte>(oidValue.Length / 2); EncodeRid(encodedBytes, ref rid); while (startPos < oidValue.Length) { rid = ParseOidRid(oidValue, ref startPos); EncodeRid(encodedBytes, ref rid); } return new byte[][] { new byte[] { (byte)DerSequenceReader.DerTag.ObjectIdentifier }, EncodeLength(encodedBytes.Count), encodedBytes.ToArray(), }; }