aboutsummaryrefslogtreecommitdiff
path: root/scripts/x509-dot.py
blob: 74977f5148343a83f0cba4d7744362b1175b5479 (plain) (blame)
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# $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
  show_issuer  = False
  show_subject = True

  cn_only      = True

  subjects = {}

  def __init__(self, filename):

    while filename.startswith("./"):
      filename = filename[2:]

    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.canonize(self.pow.getSubject())
    self.issuer  = self.canonize(self.pow.getIssuer())

    if self.subject in self.subjects:
      self.subjects[self.subject].append(self)
    else:
      self.subjects[self.subject] = [self]

  def canonize(self, name):

    if self.cn_only and len(name) == 1 and name[0][0] == "CN":
      return name[0][1]
    else:
      return name

  def set_node(self, node):

    self.node = node

  def dot(self):

    label = []

    if self.show_issuer:
      label.append(("Issuer", self.issuer))

    if self.show_subject:
      label.append(("Subject", self.subject))

    if self.show_file:
      label.append(("File", self.filename))

    if self.show_aki:
      label.append(("AKI", self.aki))

    if self.show_ski:
      label.append(("SKI", self.ski))

    print "#", repr(label)

    if len(label) > 1:
      print '%s [shape = record, label = "{%s}"];' % (self.node, "|".join("{%s|%s}" % (x, y) for x, y in label if y is not None))
    else:
      print '%s [label = "%s"];' % (self.node, label[0][1])

    for issuer in self.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, cert in enumerate(certs):
  cert.set_node("cert_%d" % i)

print """\
digraph certificates {

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

"""

for cert in certs:
  cert.dot()

print "}"