$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: - Representation of timestamps is a mess. We have four different kinds already: seconds from epoch, the the two flavors of timestamps used in ASN.1, and the timestamps used in MySQL. Need a unifying class to hide all this nastiness. POW.pkix provides conversion functions for ASN.1. MySQL timestamps appear to map to Python datetime objects. One can convert between datetime and time (seconds since epoch) objects using: time_object = time.mktime(datetime_object.timetuple()) datetime_object = datetime.datetime.fromtimestamp(int(time_object)) if one is willing to discard fractional seconds (which we probably are in this case, as they're not useful with ASN.1). No doubt there would be a way to preserserve fractional seconds if we cared. Except that the above still requires the time module's idiocy of setting the TZ environment variable to avoid having everything whacked to local time. The time.time() call itself is fine, but most of the rest of the time module is for the birds. If we're going to consolidate by subtyping datetime.datetime, we can avoid the conversion idiocy in the time module entirely by doing: time_object = int(datetime_object.strftime("%s")) which is probably even faster, albiet sillier. - Whack expiration dates of certs to match irdb valid_until value when issuing -- valid_until is optional, what do we do if it's not set? Default period in self object seems obvious answer, neither Randy nor I has thought of anything better yet. - Subsetting (req_* attributes in up-down protocol) - 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 |