Skip to content

Instantly share code, notes, and snippets.

@robbat2
Created November 5, 2020 19:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robbat2/67667bc173b4383d10f75e05b2660e65 to your computer and use it in GitHub Desktop.
Save robbat2/67667bc173b4383d10f75e05b2660e65 to your computer and use it in GitHub Desktop.
#!/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