Last active
December 1, 2023 15:56
-
-
Save James-E-A/b6705e09d99aaa7cec13c9e789a82015 to your computer and use it in GitHub Desktop.
Free OID Generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
"""DEC Sixbit bijective hierarchicial mapping | |
of the DNS namespace onto hereby-proposed child arc dns-root(52) | |
of IANA's unused OID {iso(1) identified-organization(3) iana(90)} | |
NOTE that this is a horrific hack I made as a joke / proof-of-concept / demo. | |
There are several legitimate alternatives you could consider, h/t http://oid-info.com/faq.htm#10 | |
1. IANA gives OIDs out for free, both to natural persons and to organizations, | |
of any nationality, | |
under {iso(1) identified-organization(3) dod(6) internet(1) private(4) enterprise(1)} | |
https://www.iana.org/assignments/enterprise-numbers/ | |
2. THIS ARC IS ACTUALLY SUPPOSED TO BE USED FOR DOCUMENTATION PURPOSES: | |
{joint-iso-itu-t(2) example(999)} | |
3. If you need an OID in connection with institutional research, work for an employer, | |
or even just a large open-source project, PLEASE check to see if that organization | |
already has an arc they'd like you to use for your current project! | |
4. There are a handful of organizations other than IANA which reportedly hand out OIDs | |
entirely free of charge: | |
i. The European Telecommunications Standards Institute, apparently, will assign | |
children of {itu-t(0) identified-organization(4) etsi(0)} | |
to "any organization" that requests them. | |
https://portal.etsi.org/pnns/oidlist#Reserved_Domain | |
ii. ViaSoft gives out free child OIDs within their own PEN arc, if that floats your goat. | |
They strongly urge you to think thrice whether their service is appropriate | |
for your use-case, however, given the abundance of other options. | |
It looks like small open-source and shareware projects are who they're aiming at serving. | |
https://oidplus.viathinksoft.com/oidplus/?goto=oidplus%3Acom.viathinksoft.freeoid | |
iii. Microsoft seemingly has an offline self-serve hybrid-GUID system that slaps what appears to be | |
a truncated hash of your system's original NIC's MAC address underneath an OID arc they manage. | |
They only suggest its use for Windows Server- and Active Directory-related use cases. | |
https://learn.microsoft.com/en-us/windows/win32/ad/obtaining-an-object-identifier-from-microsoft | |
5. Many countries have a National Registry that is IN PRINCIPLE available | |
to organizations with a primary business presence in the country and | |
sometimes even the general citizenry. However, most of these are either | |
hideously expensive or poorly maintained. A few representative examples: | |
- ANSI sells entries in {joint-iso-itu-t(2) country(16) us(840)} | |
for a grand or two. (That's around 6 months' median global wages! | |
All "cost recovery", of course -- the U.S. is a beacon of efficiency...) | |
It appears not to permit personal registrations. | |
https://www.ansi.org/about/roles/registration-program/organization-names | |
- Iceland's Post and Telecom Administration filed a statement alleging they'd | |
maintain registration services, but the service isn't anywhere on their website. | |
Apparently exactly one (1) company so far has figured out the process for registering an Icelandic national OID. | |
Maybe you have to send them an e-mail or something? | |
https://www.fjarskiptastofa.is/fjarskiptastofa/tolfraedi-og-gagnasafn/rafraenar-umsoknir-og-tilkynningar/tengilidaupplysingar-fyrir-netoryggissveitina-cert-is/ | |
- Organizations with enough business presence in Russia to have a TIN | |
have the option to get an OID assigned for what appears to be no charge, | |
through online registration via a web portal they've set up. | |
https://oid.iitrust.ru/faq/detail.php?ID=80 | |
- Japan: Mail a completed copy of "form 2" below in to the Ministry of Internal Affairs and Communications. | |
I'm not too keen with Google Translate, but I didn't see anything in there | |
specifying that ONLY Japanese citizens can apply... No fee schedule that I could see listed, either. | |
https://www.soumu.go.jp/main_sosiki/joho_tsusin/hyojun/pdf/object02.pdf#page=7 | |
6. You're technically allowed to pick random 128-bit integers and claim them as your own | |
underneath {joint-iso-itu-t(2) uuid(25)} | |
However, this is a crippling option as many X.509 certificate signers have length limits that | |
preclude these, which may or may not be related to much Microsoft software which also can't handle this. | |
If you go this route, everyone will make fun of you. | |
""" | |
import codecs | |
from functools import reduce as _reduce | |
from itertools import starmap as _starmap, chain as _chain, repeat as _repeat | |
from operator import eq as _eq | |
IANA = (1, 3, 90) # https://www.iana.org/domains/root | |
DEC6 = bytes(range(32, 96)).decode('ascii') # http://rabbit.eng.miami.edu/info/decchars.html | |
_ALTNICS = { | |
'opennic.org': {'bbs', 'chan', 'cyb', 'dyn', 'epic', 'fur', 'geek', 'gopher', 'indy', 'libre', 'neo', 'null', 'o', 'oss', 'oz', 'parody', 'pirate'}, | |
'emercoin.com': {'bazar', 'coin', 'emc', 'lib'}, | |
'ens.domains': {'eth'}, | |
'namecoin.org': {'bit'}, | |
'chn996.cn': {'chn'}, | |
'yeti-dns.org': set(), # included so I don't forget they exist despite the fact they're not deploying any alt-TLDs | |
'52.rkn.gov.ru': set(), # likewise | |
'handshake.org': set(), # ... | |
} | |
ALTNICS = dict((tuple(reversed(tld.upper().split('.'))), tuple(reversed(sponsor.upper().split('.')))) for sponsor, tlds in _ALTNICS.items() for tld in tlds) | |
def domain2oid(domain: str, base=IANA, subnodes=((52,), (0,)), altnics=ALTNICS) -> str: | |
"""Given DNS domain `domain`, return its "corresponding" OID""" | |
parts = domain.encode('idna').decode('ascii') # Replace unencodables with IDNA | |
parts = tuple(map(str.upper, reversed(parts.split('.')))) # Convert to upper-case tuple | |
oid = _domain2oid(parts, base, subnodes, altnics) # Convert to OID | |
return '.'.join(str(segment) for segment in oid) # Return a string | |
def _domain2oid(parts, base=(), subnodes=((),), altnics={}): | |
payload = base + subnodes[0] | |
for altroot, sponsor in altnics.items(): | |
if _istartswith(parts, altroot): | |
sponsor_base = tuple(map(crunch, sponsor)) | |
payload += _domain2oid(parts=(), base=sponsor_base, subnodes=subnodes[1:]) | |
break | |
payload += tuple(map(crunch, parts)) | |
return payload | |
def oid2domain(oid, base=IANA, subnodes=((52,), (0,)), altnics=ALTNICS, decode_idna=False): | |
"""Inverse of `domain2oid`""" | |
if isinstance(oid, str): | |
# Function allows "1.2.3.4" and (1, 2, 3, 4), for convenience | |
oid = tuple(int(i or 0) for i in oid.split('.')) | |
domain = _oid2domain(oid, base, subnodes, altnics) # Convert to domain | |
domain = '.'.join(map(str.lower, reversed(domain))) # Convert from upper-case tuple | |
if decode_idna: | |
domain = domain.encode('ascii').decode('idna') # Decode from IDNA | |
return domain | |
def _oid2domain(oid, base=(), subnodes=((),), altnics={}): | |
prefix = base + subnodes[0] | |
if not _istartswith(oid, prefix): | |
oid_printable = '.'.join(map(str, oid)) | |
prefix_printable = '.'.join(map(str, prefix)) | |
raise ValueError("%s isn't under %s" % (oid_printable, prefix_printable)) | |
oid_domain = oid[len(prefix):] | |
for altroot, sponsor in altnics.items(): | |
sponsor_base = tuple(map(crunch, sponsor)) | |
sponsor_oid_fragment = _domain2oid(parts=(), base=sponsor_base, subnodes=subnodes[1:]) | |
if _istartswith(oid_domain, sponsor_oid_fragment): | |
oid_domain = oid_domain[len(sponsor_oid_fragment):] | |
break | |
parts = tuple(map(uncrunch, oid_domain)) | |
return parts | |
def crunch(s: str) -> int: | |
"""Bijectively pack a string into a single integer as DEC SIXBIT""" | |
m = 2**6 | |
result = 0 | |
for c in map(DEC6.index, s): | |
result *= m | |
result += (c+1) | |
return result | |
def uncrunch(i: int) -> str: | |
"""Unpack an integer as a DEC SIXBIT bijectively-packed string; inverse of `crunch`""" | |
m = 2**6 | |
i = int(i) | |
result = [] | |
while i: | |
i -= 1 | |
i, c = divmod(i, m) | |
result.append(DEC6[c]) | |
return str().join(reversed(result)) | |
def _istartswith(a, b): | |
return all(_starmap(_eq, zip(_chain(a, _starmap(object, _repeat(()))), b))) | |
if __name__ == '__main__': | |
import sys | |
args = sys.argv[1:] | |
if not args: | |
# No arguments; run interactively | |
args.append(input("Enter a domain name:\n> ")) | |
# Output in TSV format | |
print(" domain name ", "OID", sep="\t") | |
for arg in args: | |
if not all(all(map(str.isdigit, part)) for part in arg.split('.')): | |
print(arg, domain2oid(arg), sep="\t") | |
else: | |
print(oid2domain(arg), arg, sep="\t") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment