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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
|
$Id$ -*- Text -*-
Python RPKI production tools.
Requires Python 2.5.
External Python packages required:
- lxml, which in turn requires the libxml2 C libraries.
FreeBSD: /usr/ports/devel/py-lxml
- MySQLdb, which in turn requires MySQL client and server. I'm
testing with MySQL 5.1.
FreeBSD: /usr/ports/databases/py-MySQLdb
- TLSLite, which pulls in other crypto packages.
FreeBSD: /usr/ports/security/py-tlslite
- Cryptlib, at the moment just to support TLSlite but may end up using
it for other things later.
FreeBSD: /usr/ports/security/cryptlib
...but the FreeBSD port doesn't (yet?) install the Python bindings,
sigh, so at the moment you have to do that by hand:
# cd /usr/ports/security/cryptlib
# make install
# cd work/bindings
# python setup.py install
# cd ../..
# make clean
- Eventually I expect that this will require an event-handling package
like Twisted, but I'm not there yet.
- The testpoke tool (up-down protocol command line test client) also
uses PyYAML, mostly for compatability with APNIC's equivalent tool.
FreeBSD: /usr/ports/devel/py-yaml
We also use a hacked copy of the Python OpenSSL Wrappers (POW)
package, but our copy has enough modifications that it's expanded in
the Subversion tree. Depending on how this all works out, I may end
up splitting the POW.pkix module out of the POW package and using it
with Cryptlib, as the POW.pkix package is 98% about doing ASN.1 in
pure Python and only 2% about any kind of crypto.
Current TO DO list:
- Revocation and CRL generation
- Need to keep data on unexpired revoked certs to generate CRL
(added a timestamp for this, sufficient?)
- Do we ever need to delay revocation of old certs to give their
replacements time to propegate?
These two imply that we need fields in child_cert table to
indicate whether a cert is dead, eg, a date field which is NULL if
the cert is still live, otherwise is the date after which it should
be added to the CRL.
Yes, but... every example of delayed revocation in the Common
Management Tasks page in the APNIC Wiki is triggered by the child,
not the parent. This suggests that revocation by the parent is
always immediate, whether it's due to overclaim or a child's class
going away or a child requesting revocation (as in key rollover).
So apparently it's the child (probably ca_detail object) that needs
timestamps. Other text in Common Management Tasks suggests that
ca_detail also needs deferred transitions from pending to active.
How to model this? An enumerated state value (already have that,
may need to rename states) and a timestamp (which may be NULL) for
next scheduled transition? Is the next state always predictable
from the current state or do we also need a next-state field?
state := pending | active | deprecated | revoked
timestamp := null | <time of next transition>
- Publication protocol and implementation thereof. Defer until core
functionality in the main engine is done.
As an interim measure, hack some kind of stub publication (not real
protocol yet, just dump to local filesystem so can see outputs and
maybe rcynic against them); this is a stop-gap to let me concentrate
on the main engine and defer work on the publication protocol and
engine.
- Publication hooks everywhere - need not wait for protocol, can just
log what would happen for now, or write to local file store (perhaps
even in a form that we can use with rcynic as a relying party).
Hooks for this go into:
- Cert publication
- CRL publication
- Manifest publication
- Withdrawal of any of the above
- Logging subsystem, including syslog support.
- Child batch processing loop, eg, regeneration or removal of expired
certs, CRL update, manifest update, etc. This should probably be an
iteration over CA objects, as the CA is the actor in pretty much
everything that might need to be done.
Figuring out whether to regenerate or remove expired certs requires
some of the same data as CRL generation.
- Code to clean up expired certs
- Code to revoke certs -- need to sort out when we do this
automatically vs waiting for explicit revoke PDU from child
- Code to generate CRLs
- Subsetting (req_* attributes in up-down protocol)
- Haven't done anything about db.commit() and db.rollback() yet, for
that matter haven't yet whacked MySQL to enable those features.
- In theory, all access to object data attributes ought to be through
accessor methods so that the .set() method can mark teh object as
SQL-dirty automagically. Not done yet. One way of hiding the
grotty bits here might be to make attributes look like elements of a
dict(), ie, implement __getitem__() and __setitem__() methods,
probably along with the other "container type" special methods for
completeness. An even easier way to do this would be to subclass
dict() and just customize __setitem__().
But all of this assumes that we really want automagic SQL-dirty, and
I'm less convinced of that now than when I made the above note.
- Test with larger data set -- Tim gave me plenty of data and I have
the low-level tools, just haven't written the glue logic to create
child objects for all the entities in the IRDB, poll on behalf of
each of them, and check the result for sanity
- Need to figure out how we're going to handle "root" case (IANA/RIR
self-signed resource cert issuing to its children). Right now this
is a separate little program, which is nice for testing but feels
wrong. As Randy puts it, this is kind of a special case of a
parent, although we might want to represent it differently. If this
were really only IANA and the RIRs, handling it as a special case
separate program might make sense, but anybody who wants to certify
private address space is going to have this problem, and the
separate daemon approach just feels wrong for that.
If it's not a separate daemon, will need left-right protocol support
to configure whatever it is we're going to configure, with all the
usual private key hygiene issues. This probably implies a level of
indirection, eg, the self-signed cert is generated in the IRBE, the
RPKI engine generates PKCS#10 for a working cert to be issued by the
self-signed cert (perhaps with RFC 3779 inheritance for everything,
to keep it small), so that the RPKI engine never needs to hold the
private key for the root.
Deferred for the moment, not sure for how long.
Once this lot is done we'll be close to something that shows at least
the basics of normal operation, albiet in a form that's not yet usable
in production.
Follow-up after that will be getting rid of remaining synchronous code
(make daemon fully event-driven, except perhaps for SQL queries),
address rollback, commit, and other data integrity issues, and see how
well the resulting code handles hosting (multiple self objects in same
daemon).
Somewhere along the way I'll need to update to the new model of trust
anchors we ended up with in Amsterdam, first step for which will
involve writing it down (well, RobK was supposed to do that, but I was
supposed to convert some pencil sketches into graphviz for him so
we're both lame on this so far). I don't think this results in major
changes, probably a few extra cert fields in the self object which we
then need to toss into the rpki.x509.X509_chain objects before
verifying CMS or TLS, and perhaps the existing TA fields in various
objects become pairs of certs instead of a single TA, but this is
mostly just generalization and reuse of existing code, no bold new
adventures.
At some point we need to do performance testing. All of our crypto is
done internally except for CMS, for which we still call the OpenSSL
CLI tool. The simplest solution would probably be to extend POW to
support CMS; cryptlib might be more entertaining solution, but am not
sure it's worth the time sink.
Although it may not be worth the effort, it'd be nice to get back to
only one crypto library. As far as I know the only things we're using
M2Crypto or cryptlib for are TLS. POW supports TLS, but tlslite
doesn't support POW. I suspect that tlslite has some kind of driver
interface, since it already supports two crypto packages, so there may
be a simple answer here. Not worth getting anywhere near this until
after making the jump to Twisted, as that might also affect this mess.
If the Python implementation ends up becoming the production version
of the engine rather than just a prototype, it might make sense to
revisit this, as the current mess of crypto libraries smells like an
accident waiting to happen.
|