Bug 1019109: Add DottedOIDToCode.py tool, r=keeler
authorBrian Smith <brian@briansmith.org>
Mon, 02 Jun 2014 10:50:04 -0700
changeset 206746 7b366010fbbcef0bc382fa6c78f5117734e012bc
parent 206745 1012d031e19cd5da73d4419f90500f7a0f608d1d
child 206747 44be87ea2e1be101218c3cb66032f599c465610a
push id494
push userraliiev@mozilla.com
push dateMon, 25 Aug 2014 18:42:16 +0000
treeherdermozilla-release@a3cc3e46b571 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskeeler
bugs1019109
milestone32.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1019109: Add DottedOIDToCode.py tool, r=keeler
security/pkix/tools/DottedOIDToCode.py
new file mode 100644
--- /dev/null
+++ b/security/pkix/tools/DottedOIDToCode.py
@@ -0,0 +1,113 @@
+# This code is made available to you under your choice of the following sets
+# of licensing terms:
+###############################################################################
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+###############################################################################
+# Copyright 2013 Mozilla Contributors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import print_function
+import sys
+
+def base128Stringified(value):
+    """
+    Encodes the given integral value into a string that is an encoded comma-
+    separated series of bytes, base-128, with all but the last byte having
+    the high bit set, in C++ hex notation, as required by the DER rules for the
+    nodes of an OID after the first two.
+
+    >>> base128Stringified(1)
+    '0x01'
+    >>> base128Stringified(10045)
+    '0xce, 0x3d'
+    """
+    if value < 0:
+        raise ValueError("An OID must have only positive-value nodes.")
+
+    format = "0x%.2x"
+
+    # least significant byte has highest bit unset
+    result = format % (value % 0x80)
+    value /= 0x80
+
+    while value != 0:
+        # other bytes have highest bit set
+        result = (format % (0x80 | (value % 0x80))) + ", " + result
+        value /= 0x80
+
+    return result
+    
+def dottedOIDToCEncoding(dottedOID):
+    """
+    Takes a dotted OID string (e.g. '1.2.840.10045.4.3.4') as input, and
+    returns a string that contains the hex encoding of the OID in C++ literal
+    notation, e.g. '0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04'. Note that
+    the ASN.1 tag and length are *not* included in the result.
+    """
+    nodes = [int(x) for x in dottedOID.strip().split(".")]
+    if len(nodes) < 2:
+        raise ValueError("An OID must have at least two nodes.")
+    if not (0 <= nodes[0] <= 2):
+        raise ValueError("The first node of an OID must be 0, 1, or 2.")
+    if not (0 <= nodes[1] <= 39):
+        # XXX: Does this restriction apply when the first part is 2?
+        raise ValueError("The second node of an OID must be 0-39.")
+    firstByte = (40 * nodes[0]) + nodes[1]
+    allStringified = [base128Stringified(x) for x in [firstByte] + nodes[2:]]
+    return ", ".join(allStringified)
+
+def specNameToCName(specName):
+    """
+    Given an string containing an ASN.1 name, returns a string that is a valid
+    C++ identifier that is as similar to that name as possible. Since most
+    ASN.1 identifiers used in PKIX specifications are legal C++ names except
+    for containing hyphens, this function just converts the hyphens to
+    underscores. This may need to be improved in the future if we encounter
+    names with other funny characters.
+    """
+    return specName.replace("-", "_")
+
+def toCode(programName, specName, dottedOID):
+    """
+    Given an ASN.1 name and a string containing the dotted representation of an
+    OID, returns a string that contains a C++ declaration for a named constant
+    that contains that OID value. Note that the ASN.1 tag and length are *not*
+    included in the result.
+
+    This:
+        toCode("DottedOIDToCode.py", "ecdsa-with-SHA512", "1.2.840.10045.4.3.4")
+    would result in a string like:
+      // python DottedOIDToCode.py ecdsa-with-SHA512 1.2.840.10045.4.3.4
+      static const uint8_t ecdsa_with_SHA512[] = {
+        0x2a, 0x86,0x48, 0xce,0x3d, 0x04, 0x03, 0x04
+      };
+    """
+    return ("  // python %s %s %s\n" +
+            "  static const uint8_t %s[] = {\n" +
+            "    %s\n" +
+            "  };\n") % (programName, specName, dottedOID,
+                         specNameToCName(specName),
+                         dottedOIDToCEncoding(dottedOID))
+
+if __name__ == "__main__":
+    if len(sys.argv) != 3:
+        print("usage:   python %s <name> <dotted-oid>" % sys.argv[0],
+              file=sys.stderr)
+        print("example: python %s ecdsa-with-SHA1 1.2.840.10045.4.1" %
+                  sys.argv[0], file=sys.stderr)
+        sys.exit(1)
+
+    print(toCode(sys.argv[0], sys.argv[1], sys.argv[2]))