00001 """
00002 Command line IR back-end control program for rpkid and pubd.
00003
00004 $Id: irbe_cli.py 2571 2009-07-04 20:13:22Z sra $
00005
00006 Copyright (C) 2009 Internet Systems Consortium ("ISC")
00007
00008 Permission to use, copy, modify, and distribute this software for any
00009 purpose with or without fee is hereby granted, provided that the above
00010 copyright notice and this permission notice appear in all copies.
00011
00012 THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00013 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00014 AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00015 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00016 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00017 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00018 PERFORMANCE OF THIS SOFTWARE.
00019
00020 Portions copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN")
00021
00022 Permission to use, copy, modify, and distribute this software for any
00023 purpose with or without fee is hereby granted, provided that the above
00024 copyright notice and this permission notice appear in all copies.
00025
00026 THE SOFTWARE IS PROVIDED "AS IS" AND ARIN DISCLAIMS ALL WARRANTIES WITH
00027 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00028 AND FITNESS. IN NO EVENT SHALL ARIN BE LIABLE FOR ANY SPECIAL, DIRECT,
00029 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00030 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00031 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00032 PERFORMANCE OF THIS SOFTWARE.
00033 """
00034
00035 import getopt, sys, textwrap
00036 import rpki.left_right, rpki.https, rpki.x509, rpki.config, rpki.log, rpki.publication
00037
00038 pem_out = None
00039
00040 class UsageWrapper(textwrap.TextWrapper):
00041 """
00042 Call interface around Python textwrap.Textwrapper class.
00043 """
00044
00045 def __call__(self, *args):
00046 """Format arguments, with TextWrapper indentation."""
00047 return self.fill(textwrap.dedent(" ".join(args)))
00048
00049 usage_fill = UsageWrapper(subsequent_indent = " " * 4)
00050
00051 class cmd_elt_mixin(object):
00052 """
00053 Protocol mix-in for command line client element PDUs.
00054 """
00055
00056
00057
00058
00059
00060
00061 excludes = ()
00062
00063 @classmethod
00064 def usage(cls):
00065 """
00066 Generate usage message for this PDU.
00067 """
00068 args = " ".join("--" + x + "=" for x in cls.attributes + cls.elements if x not in cls.excludes)
00069 bools = " ".join("--" + x for x in cls.booleans)
00070 if args and bools:
00071 return args + " " + bools
00072 else:
00073 return args or bools
00074
00075 def client_getopt(self, argv):
00076 """
00077 Parse options for this class.
00078 """
00079 opts, argv = getopt.getopt(argv, "", [x + "=" for x in self.attributes + self.elements if x not in self.excludes] + list(self.booleans))
00080 for o, a in opts:
00081 o = o[2:]
00082 handler = getattr(self, "client_query_" + o, None)
00083 if handler is not None:
00084 handler(a)
00085 elif o in self.booleans:
00086 setattr(self, o, True)
00087 else:
00088 assert o in self.attributes
00089 setattr(self, o, a)
00090 return argv
00091
00092 def client_query_bpki_cert(self, arg):
00093 """Special handler for --bpki_cert option."""
00094 self.bpki_cert = rpki.x509.X509(Auto_file = arg)
00095
00096 def client_query_glue(self, arg):
00097 """Special handler for --bpki_glue option."""
00098 self.bpki_glue = rpki.x509.X509(Auto_file = arg)
00099
00100 def client_query_bpki_cms_cert(self, arg):
00101 """Special handler for --bpki_cms_cert option."""
00102 self.bpki_cms_cert = rpki.x509.X509(Auto_file = arg)
00103
00104 def client_query_cms_glue(self, arg):
00105 """Special handler for --bpki_cms_glue option."""
00106 self.bpki_cms_glue = rpki.x509.X509(Auto_file = arg)
00107
00108 def client_query_bpki_https_cert(self, arg):
00109 """Special handler for --bpki_https_cert option."""
00110 self.bpki_https_cert = rpki.x509.X509(Auto_file = arg)
00111
00112 def client_query_https_glue(self, arg):
00113 """Special handler for --bpki_https_glue option."""
00114 self.bpki_https_glue = rpki.x509.X509(Auto_file = arg)
00115
00116 def client_reply_decode(self):
00117 pass
00118
00119 def client_reply_show(self):
00120 print self.element_name
00121 for i in self.attributes + self.elements:
00122 if getattr(self, i) is not None:
00123 print " %s: %s" % (i, getattr(self, i))
00124
00125 class cmd_msg_mixin(object):
00126 """
00127 Protocol mix-in for command line client message PDUs.
00128 """
00129
00130 @classmethod
00131 def usage(cls):
00132 """
00133 Generate usage message for this PDU.
00134 """
00135 for k, v in cls.pdus.items():
00136 print usage_fill(k, v.usage())
00137
00138
00139
00140 class self_elt(cmd_elt_mixin, rpki.left_right.self_elt):
00141 pass
00142
00143 class bsc_elt(cmd_elt_mixin, rpki.left_right.bsc_elt):
00144
00145 excludes = ("pkcs10_request",)
00146
00147 def client_query_signing_cert(self, arg):
00148 """--signing_cert option."""
00149 self.signing_cert = rpki.x509.X509(Auto_file = arg)
00150
00151 def client_query_signing_cert_crl(self, arg):
00152 """--signing_cert_crl option."""
00153 self.signing_cert_crl = rpki.x509.CRL(Auto_file = arg)
00154
00155 def client_reply_decode(self):
00156 global pem_out
00157 if pem_out is not None and self.pkcs10_request is not None:
00158 if isinstance(pem_out, str):
00159 pem_out = open(pem_out, "w")
00160 pem_out.write(self.pkcs10_request.get_PEM())
00161
00162 class parent_elt(cmd_elt_mixin, rpki.left_right.parent_elt):
00163 pass
00164
00165 class child_elt(cmd_elt_mixin, rpki.left_right.child_elt):
00166 pass
00167
00168 class repository_elt(cmd_elt_mixin, rpki.left_right.repository_elt):
00169 pass
00170
00171 class left_right_msg(cmd_msg_mixin, rpki.left_right.msg):
00172 pdus = dict((x.element_name, x)
00173 for x in (self_elt, bsc_elt, parent_elt, child_elt, repository_elt))
00174
00175 class left_right_sax_handler(rpki.left_right.sax_handler):
00176 pdu = left_right_msg
00177
00178 class left_right_cms_msg(rpki.left_right.cms_msg):
00179 saxify = left_right_sax_handler.saxify
00180
00181
00182
00183 class config_elt(cmd_elt_mixin, rpki.publication.config_elt):
00184
00185 def client_query_bpki_crl(self, arg):
00186 """Special handler for --bpki_crl option."""
00187 self.bpki_crl = rpki.x509.CRL(Auto_file = arg)
00188
00189 class client_elt(cmd_elt_mixin, rpki.publication.client_elt):
00190 pass
00191
00192 class certificate_elt(cmd_elt_mixin, rpki.publication.certificate_elt):
00193 pass
00194
00195 class crl_elt(cmd_elt_mixin, rpki.publication.crl_elt):
00196 pass
00197
00198 class manifest_elt(cmd_elt_mixin, rpki.publication.manifest_elt):
00199 pass
00200
00201 class roa_elt(cmd_elt_mixin, rpki.publication.roa_elt):
00202 pass
00203
00204 class publication_msg(cmd_msg_mixin, rpki.publication.msg):
00205 pdus = dict((x.element_name, x)
00206 for x in (config_elt, client_elt, certificate_elt, crl_elt, manifest_elt, roa_elt))
00207
00208 class publication_sax_handler(rpki.publication.sax_handler):
00209 pdu = publication_msg
00210
00211 class publication_cms_msg(rpki.publication.cms_msg):
00212 saxify = publication_sax_handler.saxify
00213
00214
00215
00216 top_opts = ["config=", "help", "pem_out=", "verbose"]
00217
00218 def usage(code = 1):
00219 print __doc__.strip()
00220 print
00221 print "Usage:"
00222 print
00223 print "# Top-level options:"
00224 print usage_fill(*["--" + x for x in top_opts])
00225 print
00226 print "# left-right protocol:"
00227 left_right_msg.usage()
00228 print
00229 print "# publication protocol:"
00230 publication_msg.usage()
00231 sys.exit(code)
00232
00233
00234
00235 def call_daemon(cms_class, client_key, client_cert, server_ta, url, q_msg):
00236 q_cms, q_xml = cms_class.wrap(q_msg, client_key, client_cert, pretty_print = True)
00237 if verbose:
00238 print q_xml
00239
00240 def done(der):
00241 r_msg, r_xml = cms_class.unwrap(der, server_ta, pretty_print = True)
00242 print r_xml
00243 for r_pdu in r_msg:
00244 r_pdu.client_reply_decode()
00245
00246 def fail(e):
00247 print "Failed: %s" % e
00248
00249 rpki.https.client(client_key = client_key,
00250 client_cert = client_cert,
00251 server_ta = server_ta,
00252 url = url,
00253 msg = q_cms,
00254 callback = done,
00255 errback = fail)
00256
00257
00258
00259 rpki.log.init("irbe_cli")
00260
00261 argv = sys.argv[1:]
00262
00263 if not argv:
00264 usage(0)
00265
00266 cfg_file = "irbe.conf"
00267 verbose = False
00268
00269 opts, argv = getopt.getopt(argv, "c:hpv?", top_opts)
00270 for o, a in opts:
00271 if o in ("-?", "-h", "--help"):
00272 usage(0)
00273 elif o in ("-c", "--config"):
00274 cfg_file = a
00275 elif o in ("-p", "--pem_out"):
00276 pem_out = a
00277 elif o in ("-v", "--verbose"):
00278 verbose = True
00279
00280 if not argv:
00281 usage(1)
00282
00283 cfg = rpki.config.parser(cfg_file, "irbe_cli")
00284
00285 q_msg_left_right = left_right_msg.query()
00286 q_msg_publication = publication_msg.query()
00287
00288 while argv:
00289 if argv[0] in left_right_msg.pdus:
00290 q_pdu = left_right_msg.pdus[argv[0]]()
00291 q_msg = q_msg_left_right
00292 elif argv[0] in publication_msg.pdus:
00293 q_pdu = publication_msg.pdus[argv[0]]()
00294 q_msg = q_msg_publication
00295 else:
00296 usage(1)
00297 argv = q_pdu.client_getopt(argv[1:])
00298 q_msg.append(q_pdu)
00299
00300 if q_msg_left_right:
00301 call_daemon(
00302 cms_class = left_right_cms_msg,
00303 client_key = rpki.x509.RSA( Auto_file = cfg.get("rpkid-irbe-key")),
00304 client_cert = rpki.x509.X509(Auto_file = cfg.get("rpkid-irbe-cert")),
00305 server_ta = (rpki.x509.X509(Auto_file = cfg.get("rpkid-bpki-ta")),
00306 rpki.x509.X509(Auto_file = cfg.get("rpkid-cert"))),
00307 url = cfg.get("rpkid-url"),
00308 q_msg = q_msg_left_right)
00309
00310 if q_msg_publication:
00311 call_daemon(
00312 cms_class = publication_cms_msg,
00313 client_key = rpki.x509.RSA( Auto_file = cfg.get("pubd-irbe-key")),
00314 client_cert = rpki.x509.X509(Auto_file = cfg.get("pubd-irbe-cert")),
00315 server_ta = (rpki.x509.X509(Auto_file = cfg.get("pubd-bpki-ta")),
00316 rpki.x509.X509(Auto_file = cfg.get("pubd-cert"))),
00317 url = cfg.get("pubd-url"),
00318 q_msg = q_msg_publication)