Skip to content
This repository has been archived by the owner on Jul 13, 2023. It is now read-only.

Commit

Permalink
feat: add a new client_certs endpoint config option
Browse files Browse the repository at this point in the history
requires whitelisted TLS client certificates for connections to the
endpoint except to health/log_check handlers

closes #498
  • Loading branch information
pjenvey committed Sep 26, 2016
1 parent e1e8a8a commit 5e63c79
Show file tree
Hide file tree
Showing 16 changed files with 573 additions and 38 deletions.
4 changes: 3 additions & 1 deletion .coveragerc
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[report]
omit = *noseplugin*
omit =
*noseplugin*
autopush/tests/certs/makecerts.py
show_missing = true
30 changes: 30 additions & 0 deletions autopush/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,33 @@ def write_error(self, code, **kwargs):
self.log.failure("Error in handler: %s" % code,
client_info=self._client_info)
self.finish()

def authenticate_peer_cert(self):
"""Authenticate the client per the configured client_certs.
Aborts the request w/ a 401 on failure.
"""
cert = self.request.connection.transport.getPeerCertificate()
assert cert, "Expected a TLS peer cert (VERIFY_FAIL_IF_NO_PEER_CERT)"

cert_signature = cert.digest('sha256')
cn = cert.get_subject().CN
auth = self.ap_settings.client_certs.get(cert_signature)
if auth is not None:
# TLS authenticated
self._client_info['tls_auth'] = auth
self._client_info['tls_auth_sha256'] = cert_signature
self._client_info['tls_auth_cn'] = cn
return

self.log.warn("Failed TLS auth",
tls_failed_sha256=cert_signature,
tls_failed_cn=cn,
client_info=self._client_info)
self.set_status(401)
# "Transport mode" isn't standard, inspired by:
# http://www6.ietf.org/mail-archive/web/tls/current/msg05589.html
self.set_header('WWW-Authenticate',
'Transport mode="tls-client-certificate"')
self.finish()
2 changes: 2 additions & 0 deletions autopush/endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ def initialize(self, ap_settings):

def prepare(self):
"""Common request preparation"""
if self.ap_settings.enable_tls_auth:
self.authenticate_peer_cert()
if self.ap_settings.cors:
self.set_header("Access-Control-Allow-Origin", "*")
self.set_header("Access-Control-Allow-Methods",
Expand Down
4 changes: 4 additions & 0 deletions autopush/log_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ def initialize(self, ap_settings):
self.ap_settings = ap_settings
self._client_info = self._init_info()

def authenticate_peer_cert(self):
"""LogCheck skips authentication checks"""
pass

@cyclone.web.asynchronous
def get(self, err_type=None):
"""HTTP GET
Expand Down
59 changes: 45 additions & 14 deletions autopush/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def add_shared_args(parser):
default="", env_var="SSL_CERT")
parser.add_argument('--ssl_dh_param',
help="SSL DH Param file (openssl dhparam 1024)",
type=str, default="", env_var="SSL_DH_PARAM")
type=str, default=None, env_var="SSL_DH_PARAM")
parser.add_argument('--router_tablename', help="DynamoDB Router Tablename",
type=str, default="router", env_var="ROUTER_TABLENAME")
parser.add_argument('--storage_tablename',
Expand Down Expand Up @@ -297,6 +297,9 @@ def _parse_endpoint(sysargs, use_files=True):
parser.add_argument('--auth_key', help='Bearer Token source key',
type=str, default=[], env_var='AUTH_KEY',
action="append")
parser.add_argument('--client_certs',
help="Allowed TLS client certificates",
type=str, env_var='CLIENT_CERTS', default="{}")

add_shared_args(parser)

Expand Down Expand Up @@ -342,6 +345,33 @@ def make_settings(args, **kwargs):
"max_data": args.max_data,
"collapsekey": args.gcm_collapsekey,
"senderIDs": sender_ids}

client_certs = None
# endpoint only
if getattr(args, 'client_certs', None):
try:
client_certs_arg = json.loads(args.client_certs)
except (ValueError, TypeError):
log.critical(format="Invalid JSON specified for client_certs")
return
if client_certs_arg:
if not args.ssl_key:
log.critical(format="client_certs specified without SSL "
"enabled (no ssl_key specified)")
return
client_certs = {}
for name, sigs in client_certs_arg.iteritems():
if not isinstance(sigs, list):
log.critical(
format="Invalid JSON specified for client_certs")
return
for sig in sigs:
sig = sig.upper()
if not (name and sig) or sig in client_certs:
log.critical(format="Invalid client_certs argument")
return
client_certs[sig] = name

if args.fcm_enabled:
# Create a common gcmclient
if not args.fcm_auth:
Expand Down Expand Up @@ -383,6 +413,7 @@ def make_settings(args, **kwargs):
resolve_hostname=args.resolve_hostname,
wake_timeout=args.wake_timeout,
ami_id=ami_id,
client_certs=client_certs,
**kwargs
)

Expand Down Expand Up @@ -472,21 +503,20 @@ def connection_main(sysargs=None, use_files=True):

# Start the WebSocket listener.
if args.ssl_key:
context_factory = AutopushSSLContextFactory(args.ssl_key,
args.ssl_cert)
if args.ssl_dh_param:
context_factory.getContext().load_tmp_dh(args.ssl_dh_param)

context_factory = AutopushSSLContextFactory(
args.ssl_key,
args.ssl_cert,
dh_file=args.ssl_dh_param)
reactor.listenSSL(args.port, site_factory, context_factory)
else:
reactor.listenTCP(args.port, site_factory)

# Start the internal routing listener.
if args.router_ssl_key:
context_factory = AutopushSSLContextFactory(args.router_ssl_key,
args.router_ssl_cert)
if args.ssl_dh_param:
context_factory.getContext().load_tmp_dh(args.ssl_dh_param)
context_factory = AutopushSSLContextFactory(
args.router_ssl_key,
args.router_ssl_cert,
dh_file=args.ssl_dh_param)
reactor.listenSSL(args.router_port, site, context_factory)
else:
reactor.listenTCP(args.router_port, site)
Expand Down Expand Up @@ -558,10 +588,11 @@ def endpoint_main(sysargs=None, use_files=True):

# start the senderIDs refresh timer
if args.ssl_key:
context_factory = AutopushSSLContextFactory(args.ssl_key,
args.ssl_cert)
if args.ssl_dh_param:
context_factory.getContext().load_tmp_dh(args.ssl_dh_param)
context_factory = AutopushSSLContextFactory(
args.ssl_key,
args.ssl_cert,
dh_file=args.ssl_dh_param,
require_peer_certs=settings.enable_tls_auth)
reactor.listenSSL(args.port, site, context_factory)
else:
reactor.listenTCP(args.port, site)
Expand Down
3 changes: 3 additions & 0 deletions autopush/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ def __init__(self,
bear_hash_key=None,
preflight_uaid="deadbeef00000000deadbeef000000000",
ami_id=None,
client_certs=None,
):
"""Initialize the Settings object
Expand Down Expand Up @@ -153,6 +154,8 @@ def __init__(self,
self.endpoint_hostname,
endpoint_port
)
self.enable_tls_auth = client_certs is not None
self.client_certs = client_certs

# Database objects
self.router_table = get_router_table(router_tablename,
Expand Down
23 changes: 23 additions & 0 deletions autopush/ssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@

class AutopushSSLContextFactory(ssl.DefaultOpenSSLContextFactory):
"""A SSL context factory"""

def __init__(self, *args, **kwargs):
self.dh_file = kwargs.pop('dh_file', None)
self.require_peer_certs = kwargs.pop('require_peer_certs', False)
ssl.DefaultOpenSSLContextFactory.__init__(self, *args, **kwargs)

def cacheContext(self):
"""Setup the main context factory with custom SSL settings"""
if self._context is None:
Expand All @@ -54,4 +60,21 @@ def cacheContext(self):
ctx.use_certificate_chain_file(self.certificateFileName)
ctx.use_privatekey_file(self.privateKeyFileName)

if self.dh_file:
ctx.load_tmp_dh(self.dh_file)

if self.require_peer_certs:
# Require peer certs but only for use by
# RequestHandlers
ctx.set_verify(
SSL.VERIFY_PEER |
SSL.VERIFY_FAIL_IF_NO_PEER_CERT |
SSL.VERIFY_CLIENT_ONCE,
self._allow_peer)

self._context = ctx

def _allow_peer(self, conn, cert, errno, depth, preverify_ok):
# skip verification: we only care about whitelisted signatures
# on file
return True
Empty file.
52 changes: 52 additions & 0 deletions autopush/tests/certs/client1.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDP2gdtxnN8cUyJ
Ix9nR3AG0DANs5jkhogfa23wiWtwHsRlACKPEtJ4ScKsofmshwf0EsC+k7jO7qOc
COscgWtjASbNBGx4lY35dOTvM3SlTnPLMbU1rOVYuGYo8l8mE9P6g63pIQPSRp5P
uQwPJVLopVlsM37F15KXrOw55+djPG76sjgLLZgLGTmVf6y4/JFgapKhktdA6W1p
zwM+dzLXFdP5P6OGp2QhFzktq4zhMnh6PwuOHjdLK+qD6Po1pPMHoSvXdUegQJXz
qOO5sxstEVhnGUcNw47jikXSpFRio3CFrvm4gFgWsiIz9H02S8520ksbuzs5462I
e9HU0OvfAgMBAAECggEAAIUnJ5srhtAxxNYVqgh/u0SiGias50V+6bU3HTb60dkB
3M7XR0xgwnRMzGnLWicsWewCF3f/KmVme2l6TSP1xNWn5zNvog2dwVYNjJuwWwmL
OKLzNSMtn782YjvZCRtbmHDj6oVuoQQUOVbZNOB/CJ4BT0gBtTUI5OBF5w8xgQoQ
hV2drp7PR/1NBSuCOxGozh7nPahn4+Ru0mCsHlEXREnofp/jmVXxkNspCpal37MP
uFfMv4eFc49dJN9sLXQj3hvfZ36iKhZvRHXaEWRlCz3X2JgyIH7T2EFon7DoU79M
NGchi8Bz2Q1jsr9OsvQ0eRKTTVs9svgMJalc167TQQKBgQDtOuzcmbVC0ItWs+oA
vGMKaksABWOtifAdK9YcJz6nw7RolZWL5kdhjNEKsLe/ge8z+WvuzqmFUk/PZvB9
sXRovilZ68/yJqXUodnbN9S81s+YKHof+nTxk/7ALqaueH2iT2j2YPzZXC3D1t7I
uQm9+6OwRqvMOREsMWIhZCv1eQKBgQDgTAuGyB3zM2bYx8iO/MVuVDyqtbYcwvUT
qOiExCmVaPYM5i/8vS/GA4fnE0p+x/MAwANcO+nMYbvJkrhoarfX8nV1P+Eu4tDV
xrIca0r0wiP0onVw7FqSQRnCXOrjVOEylPgLVGTmhqJqo1Hi6R1+4JHsHARrjbSq
YTs+autOFwKBgCWr0McrJWyJv0ayZTterv+NZ4GGWZDKMbYAKwzncnyjiDd/YXMI
y1cDTIK9E0C2+mwvdGNEsAi6zG+r8g6Tql+jqt9bofbbCkRcu0KjeAXQusB31QTU
+dMO5EpSXiegfJrUr19IgX5ms+HAcjo/n/tqRVENt+RDP6Xb5bBVvuFJAoGBAKi2
irUHMgANWf8Vx7ZGS/uBQWDm7eUUgGQZWU0EgILyQKHTQ6VIaPb5EPCvggl7PT4D
MIPgTSx/F1G4Gx3vp/m3VsKrGia6VXt3yeG2ktsobQNGcDBQmJAKh+W7HrOA1SPH
Cgz7nioIe4La9m1IC/ez1A9Vw71jCdJe8MEyi2xhAoGBALaQqDfMmn/LbzXMlkTQ
WJTKsZi5UplJvtQ7aIOL4Fgvj2WQvQ5TYZEhW9Ur9W7JSik/MwmagqYgORxaEI1B
6macvD97j5Z3rmxN4G27mPLPoAt7ntQof5cHYu3XoZbFDUbHDt6V4pgtClXoljWe
cycS7E1EDLhlDwfbaOpiWCEu
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIID8zCCAtsCEQDed3iLgJtF7olgvxiTh0nUMA0GCSqGSIb3DQEBBQUAMIGoMQsw
CQYDVQQGEwJUUjEPMA0GA1UECAwGw4dvcnVtMRQwEgYDVQQHDAtCYcWfbWFrw6fE
sTESMBAGA1UEAwwJbG9jYWxob3N0MRUwEwYDVQQKDAxNb3ppbGxhIFRlc3QxITAf
BgNVBAsMGEF1dG9wdXNoIFRlc3Qgc2VydmVyLnBlbTEkMCIGCSqGSIb3DQEJARYV
b3R0by5wdXNoQGV4YW1wbGUuY29tMCAXDTE2MDkyMTIxMzYwNloYDzIxMTYwODI4
MjEzNjA2WjCBqTELMAkGA1UEBhMCVFIxDzANBgNVBAgMBsOHb3J1bTEUMBIGA1UE
BwwLQmHFn21ha8OnxLExEjAQBgNVBAMMCWxvY2FsaG9zdDEVMBMGA1UECgwMTW96
aWxsYSBUZXN0MSIwIAYDVQQLDBlBdXRvcHVzaCBUZXN0IGNsaWVudDEucGVtMSQw
IgYJKoZIhvcNAQkBFhVvdHRvLnB1c2hAZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQDP2gdtxnN8cUyJIx9nR3AG0DANs5jkhogfa23w
iWtwHsRlACKPEtJ4ScKsofmshwf0EsC+k7jO7qOcCOscgWtjASbNBGx4lY35dOTv
M3SlTnPLMbU1rOVYuGYo8l8mE9P6g63pIQPSRp5PuQwPJVLopVlsM37F15KXrOw5
5+djPG76sjgLLZgLGTmVf6y4/JFgapKhktdA6W1pzwM+dzLXFdP5P6OGp2QhFzkt
q4zhMnh6PwuOHjdLK+qD6Po1pPMHoSvXdUegQJXzqOO5sxstEVhnGUcNw47jikXS
pFRio3CFrvm4gFgWsiIz9H02S8520ksbuzs5462Ie9HU0OvfAgMBAAGjGDAWMBQG
A1UdEQQNMAuCCWxvY2FsaG9zdDANBgkqhkiG9w0BAQUFAAOCAQEAq49K5htZ3Sw9
osT3CcKGS7m7r4FuvpL0gzE6ZDMElMK4q1u7M/DJKsXpINUqjT6cYwIJZyl02pmO
HMwuImdCWpuWSE0lUyMjVSOXAGBkkcJiVE3iP9tGH1kcCTLKoY2Ajc8w65HNxRR7
edSprTDay4Zt2ay6AG4pYl8uGN5HuvgRzyjFPjVcye4ZfF3TaJRZAMl9lJSI1qMl
DSziBbcjkx7N4TbMe8m01YYA1HmX2ZIckqEiTa05d1H548p5Dbw6GhoM/MzbEUeB
s9/XlKoFQPVADqrd6yJcTGi6mMnuKMPkUhjPjzB4ah0m4gL0oB8E/TEs7yPAYPtw
g17mJupYMw==
-----END CERTIFICATE-----
52 changes: 52 additions & 0 deletions autopush/tests/certs/client2.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDgoFA4pkilcycS
P1q8Dfd8PSTYvabFITo4Qu3aDSezhw6WnoEPSO+O2Bd/GAAmoLzmMcHPdRUsUhp7
RIuSNnd6+g6ulXyf9BFcNclBmdIhvUAvVxy4/fBoJ0or8eNgETRRHj19j7S0tAUt
oSAVW1XniSS+qX11kGsLqk6qIUl2v+p9j6GVdk1DkMO/xat2qdGpPcleexz1LD3o
Tqs2rE8hdFlbJXE5K7jN7miej1cnEb+BV99N7P/3RBwkQdAfNYyzueY/UsfCaieF
892+yo7eNA8qMZxWs86f7IjZAXJaO9sgg6YBCP+J0Oed83nc48Jq6LnCsNC9U7l5
k/UPbywZAgMBAAECggEAHXkLbZNr3sGQM9W6Owh+G4AOUJ35vs3QTMeDW+Pz/JtQ
77RWbMH+JLj3xEZK5saaYn3O10CeiZUwQlJJGeMppCohOQkGNBqbGIU6JfBf4Otq
+4srip5PJ+tX0RJI6jb3rVkRamMrq7YfI9CLXCIC0IFvH9EvU/iiAwLSlYIOmJTw
6e96Um5eIR2NjEJk2Mlv8HpJ0Ai09gDttnYFyGMUa1USGX4SeqViRN/6mb2zqvdB
OCrwhYwuPsA+WSHISKuj8xHusDCuxSTKCpYv08r/E1fMywYPP6BEp/IkrQfc6Ajv
23CJ41rNGxg3SGi1O4v1ADygUNweb44eSZyDDkyZAQKBgQDyV0U/WdRXKhk5ZTil
GWuseAt7V6UvqTHA0q7CBdDT+0ICospcENLOIul6ER16rDdAC2qeVrbReKYqska6
uVQq8513lvnt9fQwdgdH5kwSkEp4Ci0G6pnxAaJawJS3X5MdftLR2foHAaDsd59i
6qFL/IJW+YV25epJTqSXDD2iIQKBgQDtSXA3Ah/gJNlRb/U4SN750Ykq6s5Gpdww
teOph0lPyl5baDy3mJZ0pgKntMNcn66zCoI09Bg1X6uiguqjPisTfcj2OwwLA+Co
ky1iX1Tt5mcZtJvfDhlSSLvyKVGNKi2ci3/nxleRf3wYEYTV1GxsXOffc68jT5Sc
U3WN+qE6+QKBgQDVSowvCtAB+5KB2p31aZ9EB9ALOgOwJBkfHg8jw1yeBkl96mty
hngTZ9TYU9H/Uy25l5K6U5XKXYbak1f/Jfh3aT0RsXa9wriuImOcG4ye1hJE/qfM
q5Tb8tVDTLZXgq4HysSgYFpX6k4Jcet9cwaNy2uoQyr9j7QZ2zavnt1sIQKBgQCK
Ai2PAOBTOHtg/zHrs45kVDdoS7r/ohYICrJH9pRwIO5yUZUG32uamrdunRcHNySf
o5wJenLeEC++TFB184GQS5dnhv5BJdczlK5PycyWtWv/qmkB+axGjGErvlZdOUvg
Ac65mkVyLWiagw30ZCFPgVWnRBx3+CAiL/RuSHgf2QKBgQDu05Q0yiF+WzqPib0P
iFCVKUC7QuZPlDolguVu9dP50/lPnnKOrfsl0Crg61PEf0GIFTH/u6pAaOtfiNf8
7KvZFw9TfdEfOIrIAV6r+cjoOjh5ojQOqM6dbfkj49pVAP87QOiRPcCrnB06iIFU
LL3gYh24K1luBJy+Yk5UerWdbQ==
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIID8jCCAtoCEEEnv06bQUtWpwcz2aCf3oswDQYJKoZIhvcNAQEFBQAwgagxCzAJ
BgNVBAYTAlRSMQ8wDQYDVQQIDAbDh29ydW0xFDASBgNVBAcMC0JhxZ9tYWvDp8Sx
MRIwEAYDVQQDDAlsb2NhbGhvc3QxFTATBgNVBAoMDE1vemlsbGEgVGVzdDEhMB8G
A1UECwwYQXV0b3B1c2ggVGVzdCBzZXJ2ZXIucGVtMSQwIgYJKoZIhvcNAQkBFhVv
dHRvLnB1c2hAZXhhbXBsZS5jb20wIBcNMTYwOTIxMjEzNjA3WhgPMjExNjA4Mjgy
MTM2MDdaMIGpMQswCQYDVQQGEwJUUjEPMA0GA1UECAwGw4dvcnVtMRQwEgYDVQQH
DAtCYcWfbWFrw6fEsTESMBAGA1UEAwwJbG9jYWxob3N0MRUwEwYDVQQKDAxNb3pp
bGxhIFRlc3QxIjAgBgNVBAsMGUF1dG9wdXNoIFRlc3QgY2xpZW50Mi5wZW0xJDAi
BgkqhkiG9w0BCQEWFW90dG8ucHVzaEBleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAOCgUDimSKVzJxI/WrwN93w9JNi9psUhOjhC7doN
J7OHDpaegQ9I747YF38YACagvOYxwc91FSxSGntEi5I2d3r6Dq6VfJ/0EVw1yUGZ
0iG9QC9XHLj98GgnSivx42ARNFEePX2PtLS0BS2hIBVbVeeJJL6pfXWQawuqTqoh
SXa/6n2PoZV2TUOQw7/Fq3ap0ak9yV57HPUsPehOqzasTyF0WVslcTkruM3uaJ6P
VycRv4FX303s//dEHCRB0B81jLO55j9Sx8JqJ4Xz3b7Kjt40DyoxnFazzp/siNkB
clo72yCDpgEI/4nQ553zedzjwmroucKw0L1TuXmT9Q9vLBkCAwEAAaMYMBYwFAYD
VR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBBQUAA4IBAQAnqnOE8pV/C9y3
BUYS98MGoeS4Wd3jxSXSYJ0jJVRojfG0MvtJOSfZL5FCUGTmpldmw9E3IHJZNExi
k2hApnLh0xrcWepQan9eDaim+y/nPBZwxAf3kzpwwhI9pA/8pGf4pLhQmPReYacd
RWgz13JnIUAJHkOwG7Vbk6JAW74LJaiJyYe0SlbGn3TevT9wKzq63XELN0SS8tto
t9Hs0q7VbHSLZ6xdd78667LNa0VUXOuIY11C607Rdm1VvlKindazBzp44KVD/AAU
xltE1FyPs2NVzf6NiEqXOLXX47kM7CByrabpo8nfUx1w79FscHP7DfjDZZIM0qT3
Gmi/Of1Z
-----END CERTIFICATE-----
71 changes: 71 additions & 0 deletions autopush/tests/certs/makecerts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# encoding: utf-8

import uuid
from inspect import getsource

from OpenSSL.crypto import (
FILETYPE_PEM, PKey, TYPE_RSA, X509, X509Extension,
dump_certificate, dump_privatekey)

SHABREAK = 51


def make_cert(filename, cacert=None, cakey=None):
key = PKey()
key.generate_key(TYPE_RSA, 2048)

cert = X509()
subject = cert.get_subject()

subject.C = b"TR"
subject.ST = b"Çorum"
subject.L = b"Başmakçı"
subject.CN = b"localhost"
subject.O = b"Mozilla Test"
subject.OU = b"Autopush Test %s" % filename
subject.emailAddress = b"[email protected]"
subjectAltName = X509Extension(b'subjectAltName', False, b'DNS:localhost')
cert.add_extensions([subjectAltName])

cert.set_serial_number(uuid.uuid4().int)
cert.gmtime_adj_notBefore(0)
cert.gmtime_adj_notAfter(60 * 60 * 24 * 365 * 100)

cert.set_pubkey(key)

if not cacert:
# self sign
cacert = cert
cakey = key
cert.set_issuer(cacert.get_subject())
cert.sign(cakey, 'sha1')

with open(filename, 'wb') as fp:
fp.write(dump_privatekey(FILETYPE_PEM, key))
fp.write(dump_certificate(FILETYPE_PEM, cert))
return cert, key


def save_sha256(sha256):
import __main__
source = getsource(__main__)
source = source.splitlines(True)[:-2]
with open('makecerts.py', 'wb') as fp:
fp.writelines(source)
fp.write("CLIENT1_SHA256 = ('%s'\n" % sha256[:SHABREAK])
fp.write(" '%s')\n" % sha256[SHABREAK:])


def main():
# self signed
server, serverkey = make_cert("server.pem")
client1, _ = make_cert("client1.pem", cacert=server, cakey=serverkey)
make_cert("client2.pem", cacert=server, cakey=serverkey)
save_sha256(client1.digest('sha256'))


if __name__ == '__main__':
main()

CLIENT1_SHA256 = ('2C:78:32:76:D8:2E:5F:C4:C2:3B:44:57:BA:1B:AF:1F:94:'
'56:52:94:F7:5A:FE:3A:8C:7E:85:4C:6D:54:76:D2')
Loading

0 comments on commit 5e63c79

Please sign in to comment.