Revision control
Copy as Markdown
Other Tools
#!/usr/bin/python
"""
(C) 2016 Jack Lloyd
(C) 2017 Fabian Weissberg, Rohde & Schwarz Cybersecurity
Botan is released under the Simplified BSD License (see license.txt)
"""
import sys
import datetime
import re
from collections import defaultdict
def format_oid(oid):
#return '"' + oid + '"'
return "{" + oid.replace('.', ',') + '}'
def format_map(m, for_oid = False):
s = ''
for k in sorted(m.keys()):
v = m[k]
if len(s) > 0:
s += ' '
if for_oid:
s += '{ "%s", OID(%s) },\n' % (k,format_oid(v))
else:
s += '{ "%s", "%s" },\n' % (k,v)
s = s[:-2] # chomp last two chars
return s
def format_as_map(oid2str, str2oid):
return """/*
* OID maps
*
* This file was automatically generated by %s on %s
*
* All manual edits to this file will be lost. Edit the script
* then regenerate this source file.
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/oids.h>
#include <unordered_map>
namespace Botan {
std::unordered_map<std::string, std::string> OIDS::load_oid2str_map()
{
return std::unordered_map<std::string,std::string>{
%s
};
}
std::unordered_map<std::string, OID> OIDS::load_str2oid_map()
{
return std::unordered_map<std::string,OID>{
%s
};
}
}
""" % (sys.argv[0], datetime.date.today().strftime("%Y-%m-%d"),
format_map(oid2str), format_map(str2oid, True))
def format_if(m, nm,t=False):
s = ''
for k in sorted(m.keys()):
v = m[k]
if t:
s += ' if(%s == "%s") return OID(%s);\n' % (nm,k, format_oid(v))
else:
s += ' if(%s == "%s") return "%s";\n' % (nm,k, v)
s = s[:-1]
return s
def format_as_ifs(oid2str, str2oid):
return """/*
* OID maps
*
* This file was automatically generated by %s on %s
*
* All manual edits to this file will be lost. Edit the script
* then regenerate this source file.
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/oids.h>
namespace Botan {
namespace OIDS {
std::string lookup(const OID& oid)
{
const std::string oid_str = oid.to_string();
%s
return std::string();
}
OID lookup(const std::string& name)
{
%s
return OID();
}
}
}
""" % (sys.argv[0], datetime.date.today().strftime("%Y-%m-%d"),
format_if(oid2str,"oid_str"), format_if(str2oid, "name", True))
def format_dn_ub_map(dn_ub, oid2str):
s = ''
for k in sorted(dn_ub.keys()):
v = dn_ub[k]
s += ' { Botan::OID({%s}), %s }, // %s\n' % (k.replace('.',','),v,oid2str[k])
# delete last ',' and \n
idx = s.rfind(',')
if idx != -1:
s = s[:idx] + s[idx+1:-1]
return s
def format_dn_ub_as_map(dn_ub, oid2str):
return """/*
* DN_UB maps: Upper bounds on the length of DN strings
*
* This file was automatically generated by %s on %s
*
* All manual edits to this file will be lost. Edit the script
* then regenerate this source file.
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/x509_dn.h>
#include <botan/asn1_oid.h>
#include <map>
namespace {
/**
* Upper bounds for the length of distinguished name fields as given in RFC 5280, Appendix A.
* Only OIDS recognized by botan are considered, so far.
* Maps OID string representations instead of human readable strings in order
* to avoid an additional lookup.
*/
static const std::map<Botan::OID, size_t> DN_UB =
{
%s
};
}
namespace Botan {
//static
size_t X509_DN::lookup_ub(const OID& oid)
{
auto ub_entry = DN_UB.find(oid);
if(ub_entry != DN_UB.end())
{
return ub_entry->second;
}
else
{
return 0;
}
}
}
""" % (sys.argv[0], datetime.date.today().strftime("%Y-%m-%d"),
format_dn_ub_map(dn_ub,oid2str))
def format_set_map(m):
s = ''
for k in sorted(m.keys()):
v = m[k]
if len(s) > 0:
s += ' '
s += '{ "%s", {' % k
for pad in v:
s += '"%s", ' % pad
if len(v) is not 0:
s = s[:-2]
s += '} },\n'
s = s[:-1]
return s
def format_pads_as_map(sig_dict):
return """/*
* Sets of allowed padding schemes for public key types
*
* This file was automatically generated by %s on %s
*
* All manual edits to this file will be lost. Edit the script
* then regenerate this source file.
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/internal/padding.h>
#include <unordered_map>
#include <vector>
#include <string>
#include <algorithm>
namespace Botan {
namespace {
const std::unordered_map<const std::string, std::vector<std::string>> allowed_signature_paddings =
{
%s
};
}
const std::vector<std::string> get_sig_paddings(const std::string algo)
{
auto i = allowed_signature_paddings.find(algo);
if(i != allowed_signature_paddings.end())
return i->second;
return {};
}
bool sig_algo_and_pad_ok(const std::string algo, std::string padding)
{
const std::vector<std::string> pads = get_sig_paddings(algo);
return std::find(pads.begin(), pads.end(), padding) != pads.end();
}
}
""" % (sys.argv[0], datetime.date.today().strftime("%Y-%m-%d"),
format_set_map(sig_dict))
def main(args = None):
""" Print header files (oids.cpp, dn_ub.cpp) depending on the first argument and on src/build-data/oids.txt
Choose 'oids' to print oids.cpp, needs to be written to src/lib/asn1/oids.cpp
Choose 'dn_ub' to print dn_ub.cpp, needs to be written to src/lib/x509/X509_dn_ub.cpp
Choose 'pads' to print padding.cpp, needs to be written to src/lib/pk_pad/padding.cpp
"""
if args is None:
args = sys.argv
if len(args) < 2:
raise Exception("Use either 'oids', 'dn_ub', 'pads' as first argument")
oid_lines = open('./src/build-data/oids.txt').readlines()
oid_re = re.compile("^([0-9][0-9.]+) = ([A-Za-z0-9_\./\(\), -]+)(?: = )?([0-9]+)?$")
hdr_re = re.compile("^\[([a-z0-9_]+)\]$")
pad_re = re.compile("^([A-Za-z0-9_\., -]+)/([A-Za-z0-9_-]+)[A-Za-z0-9_\.\(\), -]*$")
oid2str = {}
str2oid = {}
dn_ub = {}
sig2pads = defaultdict(set)
cur_hdr = None
for line in oid_lines:
line = line.strip()
if len(line) == 0:
continue
if line[0] == '#':
continue
match = hdr_re.match(line)
if match is not None:
cur_hdr = match.group(1)
continue
match = oid_re.match(line)
if match is None:
raise Exception(line)
oid = match.group(1)
nam = match.group(2)
if oid in str2oid:
print("Duplicated OID", oid, name, oid2str[oid])
sys.exit() # hard error
else:
oid2str[oid] = nam
# parse upper bounds for DNs
if cur_hdr == "dn":
if match.lastindex < 3:
raise Exception("Could not find an upper bound for DN " + match.group(1))
dn_ub[oid] = match.group(3)
# parse signature paddings
elif cur_hdr == "signature":
pad_match = pad_re.search(nam)
if pad_match is not None:
sig2pads[pad_match.group(1)].add(pad_match.group(2))
if nam in str2oid:
#str2oid[nam] = oid
pass
else:
str2oid[nam] = oid
if args[1] == "oids":
print(format_as_map(oid2str, str2oid))
elif args[1] == "dn_ub":
print(format_dn_ub_as_map(dn_ub,oid2str))
elif args[1] == "pads":
print(format_pads_as_map(sig2pads))
else:
print("Unknown command: try oids, dn_ub, or pads")
return 0
if __name__ == '__main__':
sys.exit(main())