mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Bug 1059926: Give DottedOIDToCode.py the ability to generate more encodings, r=keeler
--HG-- extra : rebase_source : 8fabeb5802530789925ae47d1f1cc4b27e4bf899 extra : histedit_source : 1329e925ada56b29c9e05991b85b320d4ae0e3a3
This commit is contained in:
parent
6452321116
commit
127e03fe0a
@ -20,42 +20,41 @@
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import print_function
|
||||
import argparse
|
||||
import itertools
|
||||
import sys
|
||||
|
||||
def base128Stringified(value):
|
||||
def base128(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.
|
||||
Given an integral value, returns an array of the base-128 representation
|
||||
of that value, with all but the last byte having the high bit set as
|
||||
required by the DER rules for the nodes of an OID after the first two
|
||||
bytes.
|
||||
|
||||
>>> base128Stringified(1)
|
||||
'0x01'
|
||||
>>> base128Stringified(10045)
|
||||
'0xce, 0x3d'
|
||||
>>> base128(1)
|
||||
[1]
|
||||
>>> base128(10045)
|
||||
[206, 61]
|
||||
"""
|
||||
|
||||
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)
|
||||
result = [value % 0x80]
|
||||
value /= 0x80
|
||||
|
||||
while value != 0:
|
||||
# other bytes have highest bit set
|
||||
result = (format % (0x80 | (value % 0x80))) + ", " + result
|
||||
result = [0x80 | (value % 0x80)] + result
|
||||
value /= 0x80
|
||||
|
||||
return result
|
||||
|
||||
def dottedOIDToCEncoding(dottedOID):
|
||||
|
||||
def dottedOIDToEncodedArray(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.
|
||||
returns an array that contains the DER encoding of its value, without
|
||||
the tag and length (e.g. [0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04]).
|
||||
"""
|
||||
nodes = [int(x) for x in dottedOID.strip().split(".")]
|
||||
if len(nodes) < 2:
|
||||
@ -66,8 +65,26 @@ def dottedOIDToCEncoding(dottedOID):
|
||||
# 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)
|
||||
restBase128 = [base128(x) for x in nodes[2:]]
|
||||
return [firstByte] + list(itertools.chain.from_iterable(restBase128))
|
||||
|
||||
def dottedOIDToCArray(dottedOID, mode):
|
||||
"""
|
||||
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'.
|
||||
"""
|
||||
bytes = dottedOIDToEncodedArray(dottedOID)
|
||||
|
||||
if mode != "value":
|
||||
bytes = [0x06, len(bytes)] + bytes
|
||||
|
||||
if mode == "alg":
|
||||
# Wrap the DER-encoded OID in a SEQUENCE to create an
|
||||
# AlgorithmIdentifier with no parameters.
|
||||
bytes = [0x30, len(bytes)] + bytes
|
||||
|
||||
return ", ".join(["0x%.2x" % b for b in bytes])
|
||||
|
||||
def specNameToCName(specName):
|
||||
"""
|
||||
@ -80,34 +97,88 @@ def specNameToCName(specName):
|
||||
"""
|
||||
return specName.replace("-", "_")
|
||||
|
||||
def toCode(programName, specName, dottedOID):
|
||||
def toCode(programName, specName, dottedOID, mode):
|
||||
"""
|
||||
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.
|
||||
that contains that OID value. If mode is "value" then only the value of
|
||||
the OID (without the tag or length) will be included in the output. If mode
|
||||
is "tlv" then the value will be prefixed with the tag and length. If mode
|
||||
is "alg" then the value will be a complete der-encoded AlgorithmIdentifier
|
||||
with no parameters.
|
||||
|
||||
This:
|
||||
toCode("DottedOIDToCode.py", "ecdsa-with-SHA512", "1.2.840.10045.4.3.4")
|
||||
|
||||
toCode("DottedOIDToCode.py", "ecdsa-with-SHA512", "1.2.840.10045.4.3.4",
|
||||
"value")
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
// 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
|
||||
};
|
||||
|
||||
This:
|
||||
|
||||
toCode("DottedOIDToCode.py", "ecdsa-with-SHA512", "1.2.840.10045.4.3.4",
|
||||
"tlv")
|
||||
|
||||
would result in a string like:
|
||||
|
||||
// python DottedOIDToCode.py --tlv ecdsa-with-SHA512 1.2.840.10045.4.3.4
|
||||
static const uint8_t tlv_ecdsa_with_SHA512[] = {
|
||||
0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04
|
||||
};
|
||||
|
||||
This:
|
||||
|
||||
toCode("DottedOIDToCode.py", "ecdsa-with-SHA512", "1.2.840.10045.4.3.4",
|
||||
"alg")
|
||||
|
||||
would result in a string like:
|
||||
|
||||
// python DottedOIDToCode.py --alg ecdsa-with-SHA512 1.2.840.10045.4.3.4
|
||||
static const uint8_t alg_ecdsa_with_SHA512[] = {
|
||||
0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04
|
||||
};
|
||||
"""
|
||||
programNameWithOptions = programName
|
||||
varName = specNameToCName(specName)
|
||||
if mode == "tlv":
|
||||
programNameWithOptions += " --tlv"
|
||||
varName = "tlv_" + varName
|
||||
elif mode == "alg":
|
||||
programNameWithOptions += " --alg"
|
||||
varName = "alg_" + varName
|
||||
|
||||
return (" // python %s %s %s\n" +
|
||||
" static const uint8_t %s[] = {\n" +
|
||||
" %s\n" +
|
||||
" };\n") % (programName, specName, dottedOID,
|
||||
specNameToCName(specName),
|
||||
dottedOIDToCEncoding(dottedOID))
|
||||
" };\n") % (programNameWithOptions, specName, dottedOID, varName,
|
||||
dottedOIDToCArray(dottedOID, mode))
|
||||
|
||||
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)
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generate code snippets to handle OIDs in C++",
|
||||
epilog="example: python %s ecdsa-with-SHA1 1.2.840.10045.4.1"
|
||||
% sys.argv[0])
|
||||
group = parser.add_mutually_exclusive_group()
|
||||
group.add_argument("--tlv", action='store_true',
|
||||
help="Wrap the encoded OID value with the tag and length")
|
||||
group.add_argument("--alg", action='store_true',
|
||||
help="Wrap the encoded OID value in an encoded SignatureAlgorithm")
|
||||
parser.add_argument("name",
|
||||
help="The name given to the OID in the specification")
|
||||
parser.add_argument("dottedOID", metavar="dotted-oid",
|
||||
help="The OID value, in dotted notation")
|
||||
|
||||
print(toCode(sys.argv[0], sys.argv[1], sys.argv[2]))
|
||||
args = parser.parse_args()
|
||||
if args.alg:
|
||||
mode = 'alg'
|
||||
elif args.tlv:
|
||||
mode = 'tlv'
|
||||
else:
|
||||
mode = 'value'
|
||||
|
||||
print(toCode(sys.argv[0], args.name, args.dottedOID, mode))
|
||||
|
Loading…
Reference in New Issue
Block a user