# $Id$

"""
Generate .dot description of a certificate tree.
"""

import POW, sys, glob, os

class x509(object):

  ski = None
  aki = None

  show_file = True
  show_ski = False
  show_aki = False

  def __init__(self, filename):

    self.filename = filename

    f = open(filename, "rb")
    text = f.read()
    f.close()

    if text.find("-----BEGIN") >= 0:
      self.pow = POW.pemRead(POW.X509_CERTIFICATE, text)
    else:
      self.pow = POW.derRead(POW.X509_CERTIFICATE, text)

    self.extensions = dict((e[0], e[2]) for e in (self.pow.getExtension(i) for i in xrange(self.pow.countExtensions())))

    if "subjectKeyIdentifier" in self.extensions:
      self.ski = ":".join(["%02X" % ord(i) for i in self.extensions.get("subjectKeyIdentifier")[1:]])

    if "authorityKeyIdentifier" in self.extensions:
      self.aki = ":".join(["%02X" % ord(i) for i in self.extensions.get("authorityKeyIdentifier")[3:]])

    self.subject = self.pow.getSubject()
    self.issuer  = self.pow.getIssuer()

  def set_node(self, node):

    self.node = node

  def dot(self):

    s = '%s [shape = record, label = "{Issuer %s|Subject %s' % (self.node, self.issuer, self.subject)

    if self.show_file:
      s += '|File %s' % self.filename

    if self.show_aki:
      s += '|AKI %s' % self.aki

    if self.show_ski:
      s += '|SKI %s' % self.ski

    s += '}"];'

    print s

    issuer = subjects.get(self.issuer)

    if issuer is self:
      issuer = None

    if issuer is not None and self.aki is not None and issuer.ski is not None and self.aki != issuer.ski:
      issuer = None

    if issuer is not None:
      print "%s -> %s;" % (issuer.node, self.node)

    print

certs = []

for topdir in sys.argv[1:] or ["."]:
  for dirpath, dirnames, filenames in os.walk(topdir):
    certs += [x509(dirpath + "/" + filename) for filename in filenames if filename.endswith(".cer")]

for i in xrange(len(certs)):
  certs[i].set_node("cert_%d" % i)

subjects = dict((x.subject, x) for x in certs)

print """\
digraph certificates {

rotate = 90; size = "11,8.5";
splines = true;
ratio = fill;

"""

for cert in certs:
  cert.dot()

print "}"