Created
November 5, 2020 19:33
-
-
Save robbat2/67667bc173b4383d10f75e05b2660e65 to your computer and use it in GitHub Desktop.
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/python3 | |
# Utility script for interfacing with DigiCert Wildcard API | |
# Copyright 2012-2013 Robin H Johnson <robbat2@gentoo.org> | |
# Licensed under the BSD-3 license | |
# http://opensource.org/licenses/BSD-3-Clause | |
import json | |
import urllib.request, urllib.parse, urllib.error | |
import urllib.request, urllib.error, urllib.parse | |
import M2Crypto.X509 | |
import re | |
import sys | |
import os | |
APIKEY = os.environ.get('DIGICERT_WILDCARD_APIKEY', None) | |
CUSTOMER_NUMBER = os.environ.get('DIGICERT_CUSTNUM', None) | |
API_URL_BASE = 'https://www.digicert.com/clients/duplicate/api/?action=' | |
API = { | |
'list_eligible_orders': { | |
'customer_name': CUSTOMER_NUMBER, | |
'customer_api_key': APIKEY, | |
'response_type': 'json', | |
'page': None, # optional | |
}, | |
'request_wildcard_duplicate': { | |
'customer_name': CUSTOMER_NUMBER, | |
'customer_api_key': APIKEY, | |
'response_type': 'json', | |
'csr': None, | |
'order_id': None, | |
'server_type': 2, # optional | |
'sans': None, # optional | |
'comments': None, # optional | |
'use_sha2_hash': 'true', # optional | |
'increased_compatibility': 'false', # optional | |
}, | |
'download_duplicate': { | |
'customer_name': CUSTOMER_NUMBER, | |
'customer_api_key': APIKEY, | |
'response_type': 'json', | |
'cert_duplicate_id': None, | |
}, | |
} | |
# helper stuff | |
def encode(params): | |
p = {} | |
for k, v in list(params.items()): | |
if v is not None: | |
p[k] = v | |
return urllib.parse.urlencode([ | |
(k, v) for k, vs in list(p.items()) | |
for v in isinstance(vs, list) and vs or [vs] | |
]) | |
def do_request(url, params, debug=False): | |
encoded = encode(params) | |
if debug: | |
print(encode(params)) | |
resp = urllib.request.urlopen(url, data=encoded) | |
data = json.load(resp) | |
if debug: | |
print(json.dumps(data, sort_keys=True, indent=2)) | |
return data | |
def whoami(): | |
import inspect | |
return inspect.stack()[1][3] | |
def _extract_valid_sans(order_id, csr): | |
req = M2Crypto.X509.load_request_string(csr) | |
req_text = req.as_text() | |
lines = req_text.split('\n') | |
pat = re.compile('^\s+Subject:') | |
subj = [] | |
for i,v in enumerate(lines): | |
if pat.match(v): | |
_ = re.split('[,\s/]+', v) | |
_ = [i for i in _ if re.match('CN=', i)] | |
_ = [re.sub('^CN=', '', i) for i in _] | |
subj += _ | |
pat = re.compile('.*X509v3 Subject Alternative Name.*') | |
sans = '' | |
for i, v in enumerate(lines): | |
if pat.match(v): | |
sans = lines[i+1] | |
break | |
if sans is '' and len(subj) == 0: | |
raise Exception('Could not find any SANs!') | |
sans = [i for i in re.split('[,\s]', sans) if len(i) > 0] | |
bad = [] | |
for i in sans: | |
if not i.startswith('DNS:'): | |
bad.append(i) | |
if len(bad) > 0: | |
raise Exception('Bad SANs:' + ', '.join(bad)) | |
sans = [re.sub('^DNS:', '', i) for i in sans] | |
sans += subj | |
orders = _get_orders() | |
cn = orders[str(order_id)]['common_name'] | |
exclude_sans = [cn, cn.replace('*.', '')] | |
sans = set(sans) - set(exclude_sans) | |
return list(sans) | |
def _get_orders(): | |
data = list_eligible_orders() | |
orders = {} | |
for o in data['response']['return']['orders']: | |
oid = re.sub('^0+', '', o['order_id']) | |
orders[o['order_id']] = o | |
return orders | |
# API commands: | |
def list_eligible_orders(): | |
cmd = whoami() | |
url = API_URL_BASE + cmd | |
params = API[cmd] | |
params['page'] = 1 | |
data = do_request(url, params) | |
return data | |
def download_duplicate(duplicate_id): | |
cmd = whoami() | |
url = API_URL_BASE + cmd | |
params = API[cmd] | |
params['cert_duplicate_id'] = duplicate_id | |
data = do_request(url, params, debug=True) | |
return data | |
def request_wildcard_duplicate(order_id, csr, | |
server_type=2, sans=None | |
, comments='', use_sha2_hash='true', | |
increased_compatibility='false'): | |
cmd = whoami() | |
url = API_URL_BASE + cmd | |
params = API[cmd] | |
if sans is None: | |
sans = _extract_valid_sans(order_id=order_id, csr=csr) | |
sans = ','.join(sans) | |
params['order_id'] = re.sub('^0+', '', order_id) | |
params['csr'] = csr | |
params['server_type'] = server_type | |
params['sans'] = sans | |
params['comments'] = comments | |
params['use_sha2_hash'] = use_sha2_hash | |
params['increased_compatibility'] = increased_compatibility | |
data = do_request(url, params, debug=False) | |
return data | |
# ---- end of API | |
def download_all_certs(order_id, max_dupe): | |
certs = {} | |
order_id = int(re.sub('^0+', '', str(order_id))) | |
for dupe_id in range(1, max_dupe+1): | |
s = '%08d-%03d' % (order_id, dupe_id, ) | |
print('Requesting %s' % (s, )) | |
d = download_duplicate(s) | |
if d['response']['result'] == 'success': | |
certs[s] = d['response']['return'] | |
else: | |
print('Failed '+ s) | |
print(d) | |
for k,v in list(certs.items()): | |
for k2 in ['certificate', 'root', 'intermediate']: | |
f = file('%s.%s.crt' % (k, k2), 'w') | |
f.write(certs[k][k2]) | |
f.close() | |
def download_single_cert(dupe_id): | |
certs = {} | |
s = dupe_id | |
print('Requesting %s' % (s, )) | |
d = download_duplicate(s) | |
if d['response']['result'] == 'success': | |
certs[s] = d['response']['return'] | |
else: | |
print('Failed '+ s) | |
print(d) | |
for k,v in list(certs.items()): | |
for k2 in ['certificate', 'root', 'intermediate']: | |
f = file('%s.%s.crt' % (k, k2), 'w') | |
f.write(certs[k][k2]) | |
f.close() | |
if __name__ == '__main__': | |
args = sys.argv[1:] | |
if len(args) == 0 or None in (APIKEY, CUSTOMER_NUMBER): | |
print(""" | |
digicert-tool COMMAND ARGS | |
Commands & parameters: | |
list_orders | |
request ORDER_ID CSR_FILE "COMMENTS" | |
download DUPE_ID | |
You MUST set the DIGICERT_CUSTNUM & DIGICERT_WILDCARD_APIKEY | |
environment variables before running this script. | |
""") | |
sys.exit(1) | |
if False: | |
pass | |
elif args[0] == "list_orders": | |
d = _get_orders() | |
print(json.dumps(d, sort_keys=True, indent=2)) | |
elif args[0] == "request": | |
order_id = args[1] | |
csr = file(args[2]).read() | |
comments = args[3] | |
d = request_wildcard_duplicate(order_id=order_id, csr=csr, comments=comments) | |
print(d) | |
elif args[0] == "download": | |
dupe_id = args[1] | |
download_single_cert(dupe_id) | |
#list_eligible_orders() | |
#request_wildcard_duplicate(order_id='00153824', | |
# csr=file('test.csr').read(), | |
# comments='API testcase') | |
#download_all_certs(153824, 25) | |
# vim:ft=python et: |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment