--- /dev/null
+#!/usr/bin/env python
+
+from __future__ import print_function
+
+# something like openssl x509
+# but when used on a gid file we show all the parts
+
+import os
+import argparse
+
+begin = "-----BEGIN CERTIFICATE-----\n"
+end = "-----END CERTIFICATE-----"
+
+default_openssl_options = "-noout -text"
+
+tmpfilename = "/tmp/sfax509.pem"
+
+def openssl_x509_string(string, openssl_options):
+
+ if not string.startswith(begin):
+ string = begin + string
+ if not string.endswith(end):
+ string = string + end
+ with open(tmpfilename, "w") as f:
+ f.write(string)
+
+ command = "openssl x509 -in {} {}".format(tmpfilename, openssl_options)
+ os.system(command)
+
+# typically on .gids
+def openssl_x509_gid(filename, openssl_options):
+ with open(filename) as f:
+ pem = f.read()
+
+ # remove begins altogether
+ pem = pem.replace(begin, "")
+ # split along end - last item in list is '\n'
+ parts = pem.split(end)[:-1]
+
+ for part in parts:
+ print("==============================")
+ openssl_x509_string(part, openssl_options)
+
+
+example = 'sfax509.py -x "-noout -dates" foo.gid'
+
+def main():
+ parser = argparse.ArgumentParser(usage="example: {}".format(example))
+ parser.add_argument("gids", nargs='+')
+ parser.add_argument("-x", "--openssl-option", action='store',
+ default=default_openssl_options, dest='openssl_options',
+ help = "options passed to openssl x509 instead of {}"
+ .format(default_openssl_options))
+ args = parser.parse_args()
+
+ for gid in args.gids:
+ openssl_x509_gid(gid, openssl_options=args.openssl_options)
+
+if __name__ == '__main__':
+ main()
message += "]"
return message
+ def pretty_chain(self):
+ message = "{}".format(self.x509.get_subject())
+ parent = self.parent
+ while parent:
+ message += " -> {}".format(parent.x509.get_subject())
+ parent = parent.parent
+ return message
+
+ def pretty_name(self):
+ return self.get_filename() or self.pretty_chain()
+
##
# Get the public key of the certificate.
#
# @param value string containing value of the extension
def add_extension(self, name, critical, value):
- import M2Crypto
oldExtVal = None
try:
oldExtVal = self.get_extension(name)
m2x509 = M2Crypto.X509.load_cert_string(self.save_to_string())
m2pubkey = pubkey.get_m2_pubkey()
# verify it
- # verify returns -1 or 0 on failure depending on how serious the
- # error conditions are
- return m2x509.verify(m2pubkey) == 1
+ # https://www.openssl.org/docs/man1.1.0/crypto/X509_verify.html
+ # verify returns
+ # 1 if it checks out
+ # 0 if if does not
+ # -1 if it could not be checked 'for some reason'
+ m2result = m2x509.verify(m2pubkey)
+ result = m2result == 1
+ if debug_verify_chain:
+ logger.debug("Certificate.verify: <- {} (m2={}) ({} x {})"
+ .format(result, m2result, self.pretty_cert(), m2pubkey))
+ return result
# XXX alternatively, if openssl has been patched, do the much simpler:
# try:
# @param cert certificate object
def is_signed_by_cert(self, cert):
+ logger.debug("Certificate.is_signed_by_cert -> invoking verify")
k = cert.get_pubkey()
result = self.verify(k)
return result
# the public key contained in it's parent. The chain is recursed
# until a certificate is found that is signed by a trusted root.
+ logger.debug("Certificate.verify_chain {}".format(self.pretty_name()))
# verify expiration time
if self.x509.has_expired():
if debug_verify_chain:
raise CertExpired(self.pretty_cert(), "client cert")
# if this cert is signed by a trusted_cert, then we are set
- for trusted_cert in trusted_certs:
+ for i, trusted_cert in enumerate(trusted_certs, 1):
+ logger.debug("Certificate.verify_chain - trying trusted #{} : {}"
+ .format(i, trusted_cert.pretty_name()))
if self.is_signed_by_cert(trusted_cert):
# verify expiration of trusted_cert ?
if not trusted_cert.x509.has_expired():
if debug_verify_chain:
logger.debug("verify_chain: YES. Cert {} signed by trusted cert {}"
- .format(self.pretty_cert(), trusted_cert.pretty_cert()))
+ .format(self.pretty_name(), trusted_cert.pretty_name()))
return trusted_cert
else:
if debug_verify_chain:
"but that signer is expired..."
.format(self.pretty_cert(), trusted_cert.pretty_cert()))
raise CertExpired("{} signer trusted_cert {}"
- .format(self.pretty_cert(), trusted_cert.pretty_cert()))
+ .format(self.pretty_name(), trusted_cert.pretty_name()))
+ else:
+ logger.debug("verify_chain: not a direct descendant of a trusted root".
+ format(self.pretty_name(), trusted_cert))
# if there is no parent, then no way to verify the chain
if not self.parent:
if debug_verify_chain:
logger.debug("verify_chain: NO. {} has no parent "
"and issuer {} is not in {} trusted roots"
- .format(self.pretty_cert(), self.get_issuer(), len(trusted_certs)))
+ .format(self.pretty_name(), self.get_issuer(), len(trusted_certs)))
raise CertMissingParent("{}: Issuer {} is not one of the {} trusted roots, "
"and cert has no parent."
- .format(self.pretty_cert(), self.get_issuer(), len(trusted_certs)))
+ .format(self.pretty_name(), self.get_issuer(), len(trusted_certs)))
# if it wasn't signed by the parent...
if not self.is_signed_by_cert(self.parent):
if debug_verify_chain:
- logger.debug("verify_chain: NO. {} is not signed by parent {}, but by {}"
- .format(self.pretty_cert(),
- self.parent.pretty_cert(),
- self.get_issuer()))
+ logger.debug("verify_chain: NO. {} is not signed by parent {}"
+ .format(self.pretty_name(),
+ self.parent.pretty_name()))
+ self.save_to_file("/tmp/xxx-capture.pem", save_parents=True)
raise CertNotSignedByParent("{}: Parent {}, issuer {}"
- .format(self.pretty_cert(),
- self.parent.pretty_cert(),
+ .format(self.pretty_name(),
+ self.parent.pretty_name(),
self.get_issuer()))
# Confirm that the parent is a CA. Only CAs can be trusted as
# extension and hope there are no other basicConstraints
if not self.parent.isCA and not (self.parent.get_extension('basicConstraints') == 'CA:TRUE'):
logger.warn("verify_chain: cert {}'s parent {} is not a CA"
- .format(self.pretty_cert(), self.parent.pretty_cert()))
+ .format(self.pretty_name(), self.parent.pretty_name()))
raise CertNotSignedByParent("{}: Parent {} not a CA"
- .format(self.pretty_cert(), self.parent.pretty_cert()))
+ .format(self.pretty_name(), self.parent.pretty_name()))
# if the parent isn't verified...
if debug_verify_chain:
logger.debug("verify_chain: .. {}, -> verifying parent {}"
- .format(self.pretty_cert(), self.parent.pretty_cert()))
+ .format(self.pretty_name(),self.parent.pretty_name()))
self.parent.verify_chain(trusted_certs)
return