This repository has been archived by the owner on Jan 1, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathgetcert.py
112 lines (78 loc) · 3.17 KB
/
getcert.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""
Get Certificates from a request and dump them.
"""
import argparse
import sys
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
"""
Inspired by the answers from this Stackoverflow question:
https://stackoverflow.com/questions/16903528/how-to-get-response-ssl-certificate-from-requests-in-python
What follows is a series of patching the low level libraries in requests.
"""
"""
https://stackoverflow.com/a/47931103/622276
"""
sock_requests = requests.packages.urllib3.contrib.pyopenssl.WrappedSocket
def new_getpeercertchain(self, *args, **kwargs):
x509 = self.connection.get_peer_cert_chain()
return x509
sock_requests.getpeercertchain = new_getpeercertchain
"""
https://stackoverflow.com/a/16904808/622276
"""
HTTPResponse = requests.packages.urllib3.response.HTTPResponse
orig_HTTPResponse__init__ = HTTPResponse.__init__
def new_HTTPResponse__init__(self, *args, **kwargs):
orig_HTTPResponse__init__(self, *args, **kwargs)
try:
self.peercertchain = self._connection.sock.getpeercertchain()
except AttributeError:
pass
HTTPResponse.__init__ = new_HTTPResponse__init__
HTTPAdapter = requests.adapters.HTTPAdapter
orig_HTTPAdapter_build_response = HTTPAdapter.build_response
def new_HTTPAdapter_build_response(self, request, resp):
response = orig_HTTPAdapter_build_response(self, request, resp)
try:
response.peercertchain = resp.peercertchain
except AttributeError:
pass
return response
HTTPAdapter.build_response = new_HTTPAdapter_build_response
"""
Attempt to wrap in a somewhat usable CLI
"""
def cli(args):
parser = argparse.ArgumentParser(description="Request any URL and dump the certificate chain")
parser.add_argument("url", metavar="URL", type=str, nargs=1, help="Valid https URL to be handled by requests")
verify_parser = parser.add_mutually_exclusive_group(required=False)
verify_parser.add_argument("--verify", dest="verify", action="store_true", help="Explicitly set SSL verification")
verify_parser.add_argument(
"--no-verify", dest="verify", action="store_false", help="Explicitly disable SSL verification"
)
parser.set_defaults(verify=True)
return vars(parser.parse_args(args))
def dump_pem(cert, outfile="ca-chain.crt"):
"""Use the CN to dump certificate to PEM format"""
PyOpenSSL = requests.packages.urllib3.contrib.pyopenssl
pem_data = PyOpenSSL.OpenSSL.crypto.dump_certificate(PyOpenSSL.OpenSSL.crypto.FILETYPE_PEM, cert)
issuer = cert.get_issuer().get_components()
print(pem_data.decode("utf-8"))
with open(outfile, "a") as output:
for part in issuer:
output.write(part[0].decode("utf-8"))
output.write("=")
output.write(part[1].decode("utf-8"))
output.write(",\t")
output.write("\n")
output.write(pem_data.decode("utf-8"))
if __name__ == "__main__":
cli_args = cli(sys.argv[1:])
url = cli_args["url"][0]
req = requests.get(url, verify=cli_args["verify"])
for cert in req.peercertchain:
dump_pem(cert)