5
(c) by Michael Stroeder <michael@stroeder.com>
7
CGI-BIN for querying the OpenSSL certificate DB
8
Outputs empty input form if queried without parameters.
13
import sys, os, string, re, \
14
pycacnf, cgiforms, htmlbase, charset
16
from time import time,localtime,strftime,mktime
18
from pycacnf import opensslcnf, pyca_section
20
from openssl.db import \
22
DB_type,DB_exp_date,DB_rev_date,DB_serial,DB_file,DB_name,DB_number, \
23
DB_TYPE_REV,DB_TYPE_EXP,DB_TYPE_VAL, \
24
dbtime2tuple,GetEntriesbyDN,SplitDN
26
nsBaseUrl = pyca_section.get('nsBaseUrl','/')
27
nsGetCertUrl = pyca_section.get('nsGetCertUrl','get-cert.py')
28
nsViewCertUrl = pyca_section.get('nsViewCertUrl','view-cert.py')
29
ScriptMethod = pyca_section.get('ScriptMethod','POST')
30
HelpUrl = pyca_section.get('HelpUrl',nsBaseUrl)
31
searchkeys = ['CN','Email','L','O','OU','ST','C']
32
optionkeys = ['casesensitive','onlyvalid','emailcerts','servercerts']
34
##############################################################################
35
# haeufig gebrauchte Funktionen
36
##############################################################################
38
# String der Hilfe-URL zu bestimmtem Parameter zurueckgeben
39
def HelpURL(name,text):
40
return '<A HREF="%sns-enroll-help.html#%s">%s</A>' % (HelpUrl,name,charset.iso2html4(text))
42
# Ausdrucken eines leeren Eingabeformulars
43
def PrintEmptyForm(form,method='POST'):
45
print '<FORM ACTION="%s" METHOD="%s" ACCEPT-CHARSET="iso-8859-1">\n' % \
46
(os.environ.get('SCRIPT_NAME','cert-query.py'),method)
47
print '<TABLE NOBORDER><TR>'
49
print '<TD>%s</TD><TD>%s</TD>' % (form.field[i][0].inputfield(),HelpURL(form.field[i][0].name,form.field[i][0].text))
50
print '</TR>\n</TABLE>\n<TABLE>'
52
print '<TR><TD WIDTH=20%%>%s:</TD><TD>%s</TD></TR>' % (HelpURL(form.field[i][0].name,form.field[i][0].text),form.field[i][0].inputfield())
54
<INPUT TYPE="submit" VALUE="Search">
55
<INPUT TYPE="reset" VALUE="Reset">
58
# Ausgabe der Ergebnistabelle
59
def PrintFound(form,found,cellpadding=2,width=100):
61
print '<TABLE BORDER CELLPADDING=%d%% WIDTH=%d%%>' % (cellpadding,width)
62
# Tabellenueberschriften ausgeben
63
print '<TR><TH>CA name</TH><TH COLSPAN=3>Serial</TH><TH>valid<BR>until</TH>'
65
print '<TH><FONT SIZE=-1>%s</FONT></TH>' % (form.field[i][0].text)
69
for ca_name in found.keys():
70
ca = opensslcnf.getcadata(ca_name)
75
for i in found[ca_name]:
76
# Eine Tabellenzeile ausgeben
77
print '<TR><TD>%s</TD>' % (ca_name)
78
if i[DB_type]==DB_TYPE_REV:
79
print '<TD>%s</TD><TD> </TD><TD><A HREF="%s%s/%s/%s?%s">View</A></TD><TD>revoked %s</TD>' % ( \
81
nsBaseUrl,nsViewCertUrl,ca_name,certtype,i[DB_serial],
82
strftime('%Y-%m-%d %H:%M',localtime(mktime(dbtime2tuple(i[DB_rev_date]))))
84
elif i[DB_type]==DB_TYPE_EXP:
85
print '<TD>%s</TD><TD> </TD><TD><A HREF="%s%s/%s/%s?%s">View</A></TD><TD>expired %s</TD>' % ( \
87
nsBaseUrl,nsViewCertUrl,ca_name,certtype,i[DB_serial],
88
strftime('%Y-%m-%d %H:%M',localtime(mktime(dbtime2tuple(i[DB_exp_date]))))
90
elif i[DB_type]==DB_TYPE_VAL:
91
print '<TD>%s</TD><TD><A HREF="%s%s/%s/%s.crt?%s">Load</A></TD><TD><A HREF="%s%s/%s/%s?%s">View</A></TD><TD>%s</TD>' % ( \
93
nsBaseUrl,nsGetCertUrl,ca_name,certtype,i[DB_serial],
94
nsBaseUrl,nsViewCertUrl,ca_name,certtype,i[DB_serial],
95
strftime('%Y-%m-%d %H:%M',localtime(mktime(dbtime2tuple(i[DB_exp_date]))))
99
dnfield = SplitDN(i[DB_name])
100
# Spaltenelemente ausgeben
102
if dnfield.has_key(j) and dnfield[j]:
104
print '<TD><FONT SIZE=-1><A HREF="mailto:%s">%s</A></FONT></TD>' % (dnfield[j],dnfield[j])
106
print '<TD><FONT SIZE=-1>%s</FONT></TD>' % charset.asn12html4(dnfield[j])
108
# bei leeren Feldern Leerzeichen, damit Tabelle immer Raender hat
109
print '<TD> </TD>'
116
##############################################################################
118
##############################################################################
120
# form initialisieren
121
form = cgiforms.formClass(charset='iso-8859-1')
123
# Die gueltigen Inputattribute setzen
124
alphanumregex = '[0-9a-zA-Z\344\366\374\304\326\334\337�.*?_ -]*'
125
mailadrregex = '[0-9a-zA-Z@.*?=/_ -]*'
127
form.add(cgiforms.formCheckboxClass('casesensitive','case sensitive','yes',0))
128
form.add(cgiforms.formCheckboxClass('onlyvalid','only valid','yes',1))
129
form.add(cgiforms.formCheckboxClass('emailcerts','search e-mail certificates','yes',1))
130
form.add(cgiforms.formCheckboxClass('servercerts','search server certificates','yes',0))
131
form.add(cgiforms.formInputClass('CN','Common Name',30,alphanumregex))
132
form.add(cgiforms.formInputClass('Email','E-Mail',40,mailadrregex))
133
form.add(cgiforms.formInputClass('OU','Organizational Unit',30,alphanumregex))
134
form.add(cgiforms.formInputClass('O','Organization',30,alphanumregex))
135
form.add(cgiforms.formInputClass('L','Location',30,alphanumregex))
136
form.add(cgiforms.formInputClass('ST','State / Province',30,alphanumregex))
137
form.add(cgiforms.formInputClass('C','Country',2,'[a-zA-Z?]'*2))
139
# Schon Parameter vorhanden?
140
if not form.contentlength:
142
# Aufruf erfolgte ohne Parameter =>
143
# 0. Schritt: leeres Eingabeformular ausgeben
145
htmlbase.PrintHeader('Search certificates')
146
htmlbase.PrintHeading('Search certificates')
147
print """You can search for certificates in the
148
certificate database.<P>Just type in substrings or
149
regular expressions as search criteria."""
151
htmlbase.PrintFooter()
154
# Aufruf erfolgte mit Parametern
157
except cgiforms.formContentLengthException,e:
158
htmlbase.PrintErrorMsg('Content length invalid.')
160
except cgiforms.formParamNameException,e:
161
htmlbase.PrintErrorMsg('Unknown parameter "%s".' % (e.name))
163
except cgiforms.formParamContentException,e:
164
htmlbase.PrintErrorMsg('Content of field "%s" has invalid format.' % (e.text))
166
except cgiforms.formParamStructException,e:
167
htmlbase.PrintErrorMsg('Too many (%d) parameters for field "%s".' % (e.count,e.name))
169
except cgiforms.formParamLengthException,e:
170
htmlbase.PrintErrorMsg('Content too long. Field "%s" has %d characters.' % (e.text,e.length))
173
htmlbase.PrintErrorMsg('Unknown exception.')
178
# Anfrage zurecht formatieren
179
query = empty_DN_dict
182
query[i] = form.field[i][0].content
185
old_db_filenames = []
187
if 'casesensitive' in form.inputkeys:
188
casesensitive = form.field['casesensitive'][0].content=='yes'
191
if 'onlyvalid' in form.inputkeys:
192
onlyvalid = form.field['onlyvalid'][0].content=='yes'
195
if 'emailcerts' in form.inputkeys:
196
emailcerts = form.field['emailcerts'][0].content=='yes'
199
if 'servercerts' in form.inputkeys:
200
servercerts = form.field['servercerts'][0].content=='yes'
204
ca_names = opensslcnf.sectionkeys.get('ca',[])
206
for ca_name in ca_names:
208
ca = opensslcnf.getcadata(ca_name)
210
# Ist der Zertifikattyp 'S/MIME for client use' ?
211
if (emailcerts and ca.isemailcert()) or \
212
(servercerts and ca.isservercert()):
214
# Stammverzeichnis der CA
215
# Zertifikat-DB schon vorher mal behandelt?
216
if not ca.database in old_db_filenames:
217
old_db_filenames.append(ca.database)
218
if os.path.isfile(ca.database):
221
found[ca_name] = GetEntriesbyDN(
224
form.field['casesensitive'][0].content=='yes',
225
form.field['onlyvalid'][0].content=='yes'
228
htmlbase.PrintErrorMsg('Error parsing regular expression.')
233
htmlbase.PrintErrorMsg('No matching entries found.')
236
# Ausgabe des Suchergebnisses
237
htmlbase.PrintHeader('Search results')
238
PrintFound(form,found)
239
htmlbase.PrintFooter()