aboutsummaryrefslogtreecommitdiff
path: root/rp/utils
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2015-10-26 06:29:00 +0000
committerRob Austein <sra@hactrn.net>2015-10-26 06:29:00 +0000
commitb46deb1417dc3596e9ac9fe2fe8cc0b7f42457e7 (patch)
treeca0dc0276d1adc168bc3337ce0564c4ec4957c1b /rp/utils
parent397beaf6d9900dc3b3cb612c89ebf1d57b1d16f6 (diff)
"Any programmer who fails to comply with the standard naming, formatting,
or commenting conventions should be shot. If it so happens that it is inconvenient to shoot him, then he is to be politely requested to recode his program in adherence to the above standard." -- Michael Spier, Digital Equipment Corporation svn path=/branches/tk705/; revision=6152
Diffstat (limited to 'rp/utils')
-rwxr-xr-xrp/utils/find_roa202
-rwxr-xr-xrp/utils/hashdir50
-rwxr-xr-xrp/utils/print_roa70
-rwxr-xr-xrp/utils/print_rpki_manifest34
-rwxr-xr-xrp/utils/scan_roas44
-rwxr-xr-xrp/utils/scan_routercerts28
-rwxr-xr-xrp/utils/uri70
7 files changed, 249 insertions, 249 deletions
diff --git a/rp/utils/find_roa b/rp/utils/find_roa
index 2b537bf4..15a2f25f 100755
--- a/rp/utils/find_roa
+++ b/rp/utils/find_roa
@@ -28,109 +28,109 @@ import rpki.oids
def check_dir(s):
- if os.path.isdir(s):
- return os.path.abspath(s)
- else:
- raise argparse.ArgumentTypeError("%r is not a directory" % s)
+ if os.path.isdir(s):
+ return os.path.abspath(s)
+ else:
+ raise argparse.ArgumentTypeError("%r is not a directory" % s)
def filename_to_uri(filename):
- if not filename.startswith(args.rcynic_dir):
- raise ValueError
- return "rsync://" + filename[len(args.rcynic_dir):].lstrip("/")
+ if not filename.startswith(args.rcynic_dir):
+ raise ValueError
+ return "rsync://" + filename[len(args.rcynic_dir):].lstrip("/")
def uri_to_filename(uri):
- if not uri.startswith("rsync://"):
- raise ValueError
- return os.path.join(args.rcynic_dir, uri[len("rsync://"):])
+ if not uri.startswith("rsync://"):
+ raise ValueError
+ return os.path.join(args.rcynic_dir, uri[len("rsync://"):])
class Prefix(object):
- """
- One prefix parsed from the command line.
- """
-
- def __init__(self, val):
- addr, length = val.split("/")
- length, sep, maxlength = length.partition("-") # pylint: disable=W0612
- self.prefix = rpki.POW.IPAddress(addr)
- self.length = int(length)
- self.maxlength = int(maxlength) if maxlength else self.length
- if self.maxlength < self.length or self.length < 0 or self.length > self.prefix.bits:
- raise ValueError
- if self.prefix & ((1 << (self.prefix.bits - self.length)) - 1) != 0:
- raise ValueError
-
- def matches(self, roa): # pylint: disable=W0621
- return any(self.prefix == prefix and
- self.length == length and
- (not args.match_maxlength or
- self.maxlength == maxlength or
- (maxlength is None and
- self.length == self.maxlength))
- for prefix, length, maxlength in roa.prefixes)
+ """
+ One prefix parsed from the command line.
+ """
+
+ def __init__(self, val):
+ addr, length = val.split("/")
+ length, sep, maxlength = length.partition("-") # pylint: disable=W0612
+ self.prefix = rpki.POW.IPAddress(addr)
+ self.length = int(length)
+ self.maxlength = int(maxlength) if maxlength else self.length
+ if self.maxlength < self.length or self.length < 0 or self.length > self.prefix.bits:
+ raise ValueError
+ if self.prefix & ((1 << (self.prefix.bits - self.length)) - 1) != 0:
+ raise ValueError
+
+ def matches(self, roa): # pylint: disable=W0621
+ return any(self.prefix == prefix and
+ self.length == length and
+ (not args.match_maxlength or
+ self.maxlength == maxlength or
+ (maxlength is None and
+ self.length == self.maxlength))
+ for prefix, length, maxlength in roa.prefixes)
class ROA(rpki.POW.ROA): # pylint: disable=W0232
- """
- Aspects of a ROA that we care about.
- """
-
- @classmethod
- def parse(cls, fn): # pylint: disable=W0621
- assert fn.startswith(args.rcynic_dir)
- self = cls.derReadFile(fn)
- self.fn = fn
- self.extractWithoutVerifying()
- v4, v6 = self.getPrefixes()
- self.prefixes = (v4 or ()) + (v6 or ())
- return self
-
- @property
- def uri(self):
- return filename_to_uri(self.fn)
-
- @property
- def formatted_prefixes(self):
- for prefix in self.prefixes:
- if prefix[2] is None or prefix[1] == prefix[2]:
- yield "%s/%d" % (prefix[0], prefix[1])
- else:
- yield "%s/%d-%d" % (prefix[0], prefix[1], prefix[2])
-
- def __str__(self):
- prefixes = " ".join(self.formatted_prefixes)
- plural = "es" if " " in prefixes else ""
- if args.show_inception:
- return "signingTime %s ASN %s prefix%s %s" % (self.signingTime(), self.getASID(), plural, prefixes)
- else:
- return "ASN %s prefix%s %s" % (self.getASID(), plural, prefixes)
-
- def show(self):
- print "%s %s" % (self, self.fn if args.show_filenames else self.uri)
-
- def show_expiration(self):
- print self
- x = self.certs()[0]
- fn = self.fn # pylint: disable=W0621
- uri = self.uri
- while uri is not None:
- name = fn if args.show_filenames else uri
- if args.show_inception:
- print "notBefore", x.getNotBefore(), "notAfter", x.getNotAfter(), name
- else:
- print x.getNotAfter(), name
- for uri in x.getAIA() or ():
- if uri.startswith("rsync://"):
- break
- else:
- break
- fn = uri_to_filename(uri)
- if not os.path.exists(fn):
- print "***** MISSING ******", uri
- break
- x = rpki.POW.X509.derReadFile(fn)
- print
+ """
+ Aspects of a ROA that we care about.
+ """
+
+ @classmethod
+ def parse(cls, fn): # pylint: disable=W0621
+ assert fn.startswith(args.rcynic_dir)
+ self = cls.derReadFile(fn)
+ self.fn = fn
+ self.extractWithoutVerifying()
+ v4, v6 = self.getPrefixes()
+ self.prefixes = (v4 or ()) + (v6 or ())
+ return self
+
+ @property
+ def uri(self):
+ return filename_to_uri(self.fn)
+
+ @property
+ def formatted_prefixes(self):
+ for prefix in self.prefixes:
+ if prefix[2] is None or prefix[1] == prefix[2]:
+ yield "%s/%d" % (prefix[0], prefix[1])
+ else:
+ yield "%s/%d-%d" % (prefix[0], prefix[1], prefix[2])
+
+ def __str__(self):
+ prefixes = " ".join(self.formatted_prefixes)
+ plural = "es" if " " in prefixes else ""
+ if args.show_inception:
+ return "signingTime %s ASN %s prefix%s %s" % (self.signingTime(), self.getASID(), plural, prefixes)
+ else:
+ return "ASN %s prefix%s %s" % (self.getASID(), plural, prefixes)
+
+ def show(self):
+ print "%s %s" % (self, self.fn if args.show_filenames else self.uri)
+
+ def show_expiration(self):
+ print self
+ x = self.certs()[0]
+ fn = self.fn # pylint: disable=W0621
+ uri = self.uri
+ while uri is not None:
+ name = fn if args.show_filenames else uri
+ if args.show_inception:
+ print "notBefore", x.getNotBefore(), "notAfter", x.getNotAfter(), name
+ else:
+ print x.getNotAfter(), name
+ for uri in x.getAIA() or ():
+ if uri.startswith("rsync://"):
+ break
+ else:
+ break
+ fn = uri_to_filename(uri)
+ if not os.path.exists(fn):
+ print "***** MISSING ******", uri
+ break
+ x = rpki.POW.X509.derReadFile(fn)
+ print
parser = argparse.ArgumentParser(description = __doc__)
@@ -145,14 +145,14 @@ args = parser.parse_args()
# If there's some way to automate this in the parser, I don't know what it is, so just catch it here.
if args.all != (not args.prefixes):
- parser.error("--all and prefix list are mutually exclusive")
+ parser.error("--all and prefix list are mutually exclusive")
for root, dirs, files in os.walk(args.rcynic_dir):
- for fn in files:
- if fn.endswith(".roa"):
- roa = ROA.parse(os.path.join(root, fn))
- if args.all or any(prefix.matches(roa) for prefix in args.prefixes):
- if args.show_expiration:
- roa.show_expiration()
- else:
- roa.show()
+ for fn in files:
+ if fn.endswith(".roa"):
+ roa = ROA.parse(os.path.join(root, fn))
+ if args.all or any(prefix.matches(roa) for prefix in args.prefixes):
+ if args.show_expiration:
+ roa.show_expiration()
+ else:
+ roa.show()
diff --git a/rp/utils/hashdir b/rp/utils/hashdir
index d3fe393c..c7c18350 100755
--- a/rp/utils/hashdir
+++ b/rp/utils/hashdir
@@ -30,10 +30,10 @@ import argparse
import rpki.POW
def check_dir(s):
- if os.path.isdir(s):
- return os.path.abspath(s)
- else:
- raise argparse.ArgumentTypeError("%r is not a directory" % s)
+ if os.path.isdir(s):
+ return os.path.abspath(s)
+ else:
+ raise argparse.ArgumentTypeError("%r is not a directory" % s)
parser = argparse.ArgumentParser(description = __doc__)
parser.add_argument("-v", "--verbose", action = "store_true", help = "whistle while you work")
@@ -42,26 +42,26 @@ parser.add_argument("output_dir", help = "name of output directory to create")
args = parser.parse_args()
if not os.path.isdir(args.output_dir):
- os.makedirs(args.output_dir)
+ os.makedirs(args.output_dir)
for root, dirs, files in os.walk(args.rcynic_dir):
- for ifn in files:
- ifn = os.path.join(root, ifn)
- if ifn.endswith(".cer"):
- obj = rpki.POW.X509.derReadFile(ifn)
- fmt = "%08x.%%d" % obj.getSubjectHash()
- elif ifn.endswith(".crl"):
- obj = rpki.POW.CRL.derReadFile(ifn)
- fmt = "%08x.r%%d" % obj.getIssuerHash()
- else:
- continue
- for i in xrange(1000000):
- ofn = os.path.join(args.output_dir, fmt % i)
- if not os.path.exists(ofn):
- with open(ofn, "w") as f:
- f.write(obj.pemWrite())
- if args.verbose:
- print ofn, "<=", ifn
- break
- else:
- sys.exit("No path name available for %s (%s)" % (ifn, ofn))
+ for ifn in files:
+ ifn = os.path.join(root, ifn)
+ if ifn.endswith(".cer"):
+ obj = rpki.POW.X509.derReadFile(ifn)
+ fmt = "%08x.%%d" % obj.getSubjectHash()
+ elif ifn.endswith(".crl"):
+ obj = rpki.POW.CRL.derReadFile(ifn)
+ fmt = "%08x.r%%d" % obj.getIssuerHash()
+ else:
+ continue
+ for i in xrange(1000000):
+ ofn = os.path.join(args.output_dir, fmt % i)
+ if not os.path.exists(ofn):
+ with open(ofn, "w") as f:
+ f.write(obj.pemWrite())
+ if args.verbose:
+ print ofn, "<=", ifn
+ break
+ else:
+ sys.exit("No path name available for %s (%s)" % (ifn, ofn))
diff --git a/rp/utils/print_roa b/rp/utils/print_roa
index c96a7c66..78ae244f 100755
--- a/rp/utils/print_roa
+++ b/rp/utils/print_roa
@@ -26,18 +26,18 @@ import rpki.POW
class ROA(rpki.POW.ROA): # pylint: disable=W0232
- @staticmethod
- def _format_prefix(p):
- if p[2] in (None, p[1]):
- return "%s/%d" % (p[0], p[1])
- else:
- return "%s/%d-%d" % (p[0], p[1], p[2])
+ @staticmethod
+ def _format_prefix(p):
+ if p[2] in (None, p[1]):
+ return "%s/%d" % (p[0], p[1])
+ else:
+ return "%s/%d-%d" % (p[0], p[1], p[2])
- def parse(self):
- self.extractWithoutVerifying()
- v4, v6 = self.getPrefixes()
- self.v4_prefixes = [self._format_prefix(p) for p in (v4 or ())]
- self.v6_prefixes = [self._format_prefix(p) for p in (v6 or ())]
+ def parse(self):
+ self.extractWithoutVerifying()
+ v4, v6 = self.getPrefixes()
+ self.v4_prefixes = [self._format_prefix(p) for p in (v4 or ())]
+ self.v6_prefixes = [self._format_prefix(p) for p in (v6 or ())]
parser = argparse.ArgumentParser(description = __doc__)
parser.add_argument("-b", "--brief", action = "store_true", help = "show only ASN and prefix(es)")
@@ -47,27 +47,27 @@ parser.add_argument("roas", nargs = "+", type = ROA.derReadFile, help = "ROA(s)
args = parser.parse_args()
for roa in args.roas:
- roa.parse()
- if args.brief:
- if args.signing_time:
- print roa.signingTime(),
- print roa.getASID(), " ".join(roa.v4_prefixes + roa.v6_prefixes)
- else:
- print "ROA Version: ", roa.getVersion()
- print "SigningTime: ", roa.signingTime()
- print "asID: ", roa.getASID()
- if roa.v4_prefixes:
- print " addressFamily:", 1
- for prefix in roa.v4_prefixes:
- print " IPAddress:", prefix
- if roa.v6_prefixes:
- print " addressFamily:", 2
- for prefix in roa.v6_prefixes:
- print " IPAddress:", prefix
- if args.cms:
- print roa.pprint()
- for cer in roa.certs():
- print cer.pprint()
- for crl in roa.crls():
- print crl.pprint()
- print
+ roa.parse()
+ if args.brief:
+ if args.signing_time:
+ print roa.signingTime(),
+ print roa.getASID(), " ".join(roa.v4_prefixes + roa.v6_prefixes)
+ else:
+ print "ROA Version: ", roa.getVersion()
+ print "SigningTime: ", roa.signingTime()
+ print "asID: ", roa.getASID()
+ if roa.v4_prefixes:
+ print " addressFamily:", 1
+ for prefix in roa.v4_prefixes:
+ print " IPAddress:", prefix
+ if roa.v6_prefixes:
+ print " addressFamily:", 2
+ for prefix in roa.v6_prefixes:
+ print " IPAddress:", prefix
+ if args.cms:
+ print roa.pprint()
+ for cer in roa.certs():
+ print cer.pprint()
+ for crl in roa.crls():
+ print crl.pprint()
+ print
diff --git a/rp/utils/print_rpki_manifest b/rp/utils/print_rpki_manifest
index ce9b25ea..83e5c16e 100755
--- a/rp/utils/print_rpki_manifest
+++ b/rp/utils/print_rpki_manifest
@@ -31,20 +31,20 @@ parser.add_argument("manifests", nargs = "+", type = rpki.POW.Manifest.derReadFi
args = parser.parse_args()
for mft in args.manifests:
- mft.extractWithoutVerifying()
- print "Manifest Version:", mft.getVersion()
- print "SigningTime: ", mft.signingTime()
- print "Number: ", mft.getManifestNumber()
- print "thisUpdate: ", mft.getThisUpdate()
- print "nextUpdate: ", mft.getNextUpdate()
- print "fileHashAlg: ", rpki.oids.oid2name(mft.getAlgorithm())
- for i, fah in enumerate(mft.getFiles()):
- name, obj_hash = fah
- print "fileList[%3d]: %s %s" % (i, ":".join(("%02X" % ord(h) for h in obj_hash)), name)
- if args.cms:
- print mft.pprint()
- for cer in mft.certs():
- print cer.pprint()
- for crl in mft.crls():
- print crl.pprint()
- print
+ mft.extractWithoutVerifying()
+ print "Manifest Version:", mft.getVersion()
+ print "SigningTime: ", mft.signingTime()
+ print "Number: ", mft.getManifestNumber()
+ print "thisUpdate: ", mft.getThisUpdate()
+ print "nextUpdate: ", mft.getNextUpdate()
+ print "fileHashAlg: ", rpki.oids.oid2name(mft.getAlgorithm())
+ for i, fah in enumerate(mft.getFiles()):
+ name, obj_hash = fah
+ print "fileList[%3d]: %s %s" % (i, ":".join(("%02X" % ord(h) for h in obj_hash)), name)
+ if args.cms:
+ print mft.pprint()
+ for cer in mft.certs():
+ print cer.pprint()
+ for crl in mft.crls():
+ print crl.pprint()
+ print
diff --git a/rp/utils/scan_roas b/rp/utils/scan_roas
index 4f3dc7f0..f4489f32 100755
--- a/rp/utils/scan_roas
+++ b/rp/utils/scan_roas
@@ -27,29 +27,29 @@ import argparse
import rpki.POW
def check_dir(d):
- if not os.path.isdir(d):
- raise argparse.ArgumentTypeError("%r is not a directory" % d)
- return d
+ if not os.path.isdir(d):
+ raise argparse.ArgumentTypeError("%r is not a directory" % d)
+ return d
class ROA(rpki.POW.ROA): # pylint: disable=W0232
- @classmethod
- def parse(cls, fn): # pylint: disable=W0621
- self = cls.derReadFile(fn)
- self.extractWithoutVerifying()
- return self
+ @classmethod
+ def parse(cls, fn): # pylint: disable=W0621
+ self = cls.derReadFile(fn)
+ self.extractWithoutVerifying()
+ return self
- @property
- def prefixes(self):
- v4, v6 = self.getPrefixes()
- for prefix, length, maxlength in (v4 or ()) + (v6 or ()):
- if maxlength is None or length == maxlength:
- yield "%s/%d" % (prefix, length)
- else:
- yield "%s/%d-%d" % (prefix, length, maxlength)
+ @property
+ def prefixes(self):
+ v4, v6 = self.getPrefixes()
+ for prefix, length, maxlength in (v4 or ()) + (v6 or ()):
+ if maxlength is None or length == maxlength:
+ yield "%s/%d" % (prefix, length)
+ else:
+ yield "%s/%d-%d" % (prefix, length, maxlength)
- def __str__(self):
- return "%s %s %s" % (self.signingTime(), self.getASID(), " ".join(self.prefixes))
+ def __str__(self):
+ return "%s %s %s" % (self.signingTime(), self.getASID(), " ".join(self.prefixes))
parser = argparse.ArgumentParser(description = __doc__)
parser.add_argument("rcynic_dir", nargs = "+", type = check_dir,
@@ -57,7 +57,7 @@ parser.add_argument("rcynic_dir", nargs = "+", type = check_dir,
args = parser.parse_args()
for rcynic_dir in args.rcynic_dir:
- for root, dirs, files in os.walk(rcynic_dir):
- for fn in files:
- if fn.endswith(".roa"):
- print ROA.parse(os.path.join(root, fn))
+ for root, dirs, files in os.walk(rcynic_dir):
+ for fn in files:
+ if fn.endswith(".roa"):
+ print ROA.parse(os.path.join(root, fn))
diff --git a/rp/utils/scan_routercerts b/rp/utils/scan_routercerts
index 081a6293..9a13d7a9 100755
--- a/rp/utils/scan_routercerts
+++ b/rp/utils/scan_routercerts
@@ -28,9 +28,9 @@ import rpki.POW
import rpki.oids
def check_dir(s):
- if not os.path.isdir(s):
- raise argparse.ArgumentTypeError("%r is not a directory" % s)
- return s
+ if not os.path.isdir(s):
+ raise argparse.ArgumentTypeError("%r is not a directory" % s)
+ return s
parser = argparse.ArgumentParser(description = __doc__)
parser.add_argument("rcynic_dir", type = check_dir, help = "rcynic authenticated output directory")
@@ -38,20 +38,20 @@ args = parser.parse_args()
for root, dirs, files in os.walk(args.rcynic_dir):
- for fn in files:
+ for fn in files:
- if not fn.endswith(".cer"):
- continue
+ if not fn.endswith(".cer"):
+ continue
- x = rpki.POW.X509.derReadFile(os.path.join(root, fn))
+ x = rpki.POW.X509.derReadFile(os.path.join(root, fn))
- if rpki.oids.id_kp_bgpsec_router not in (x.getEKU() or ()):
- continue
+ if rpki.oids.id_kp_bgpsec_router not in (x.getEKU() or ()):
+ continue
- sys.stdout.write(base64.urlsafe_b64encode(x.getSKI()).rstrip("="))
+ sys.stdout.write(base64.urlsafe_b64encode(x.getSKI()).rstrip("="))
- for min_asn, max_asn in x.getRFC3779()[0]:
- for asn in xrange(min_asn, max_asn + 1):
- sys.stdout.write(" %s" % asn)
+ for min_asn, max_asn in x.getRFC3779()[0]:
+ for asn in xrange(min_asn, max_asn + 1):
+ sys.stdout.write(" %s" % asn)
- sys.stdout.write(" %s\n" % base64.b64encode(x.getPublicKey().derWritePublic()))
+ sys.stdout.write(" %s\n" % base64.b64encode(x.getPublicKey().derWritePublic()))
diff --git a/rp/utils/uri b/rp/utils/uri
index df6e710b..4fecf73a 100755
--- a/rp/utils/uri
+++ b/rp/utils/uri
@@ -29,44 +29,44 @@ import rpki.POW
class Certificate(object):
- @staticmethod
- def first_whatever(uris, prefix):
- if uris is not None:
- for uri in uris:
- if uri.startswith(prefix):
- return uri
- return None
+ @staticmethod
+ def first_whatever(uris, prefix):
+ if uris is not None:
+ for uri in uris:
+ if uri.startswith(prefix):
+ return uri
+ return None
- def first_rsync(self, uris):
- return self.first_whatever(uris, "rsync://")
+ def first_rsync(self, uris):
+ return self.first_whatever(uris, "rsync://")
- def first_http(self, uris):
- return self.first_whatever(uris, "http://")
+ def first_http(self, uris):
+ return self.first_whatever(uris, "http://")
- def __init__(self, fn):
- try:
- x = rpki.POW.X509.derReadFile(fn)
- except: # pylint: disable=W0702
- try:
- cms = rpki.POW.CMS.derReadFile(fn)
- cms.extractWithoutVerifying()
- x = cms.certs()[0]
- except:
- raise ValueError
- sia = x.getSIA() or (None, None, None, None)
- self.fn = fn
- self.uris = (
- ("AIA:caIssuers", self.first_rsync(x.getAIA())),
- ("SIA:caRepository", self.first_rsync(sia[0])),
- ("SIA:rpkiManifest", self.first_rsync(sia[1])),
- ("SIA:signedObject", self.first_rsync(sia[2])),
- ("SIA:rpkiNotify", self.first_http(sia[3])),
- ("CRLDP", self.first_rsync(x.getCRLDP())))
+ def __init__(self, fn):
+ try:
+ x = rpki.POW.X509.derReadFile(fn)
+ except: # pylint: disable=W0702
+ try:
+ cms = rpki.POW.CMS.derReadFile(fn)
+ cms.extractWithoutVerifying()
+ x = cms.certs()[0]
+ except:
+ raise ValueError
+ sia = x.getSIA() or (None, None, None, None)
+ self.fn = fn
+ self.uris = (
+ ("AIA:caIssuers", self.first_rsync(x.getAIA())),
+ ("SIA:caRepository", self.first_rsync(sia[0])),
+ ("SIA:rpkiManifest", self.first_rsync(sia[1])),
+ ("SIA:signedObject", self.first_rsync(sia[2])),
+ ("SIA:rpkiNotify", self.first_http(sia[3])),
+ ("CRLDP", self.first_rsync(x.getCRLDP())))
- def __str__(self):
- words = [self.fn] if args.single_line else ["File: " + self.fn]
- words.extend(" %s: %s" % (tag, uri) for tag, uri in self.uris if uri is not None)
- return ("" if args.single_line else "\n").join(words)
+ def __str__(self):
+ words = [self.fn] if args.single_line else ["File: " + self.fn]
+ words.extend(" %s: %s" % (tag, uri) for tag, uri in self.uris if uri is not None)
+ return ("" if args.single_line else "\n").join(words)
parser = argparse.ArgumentParser(description = __doc__)
parser.add_argument("-s", "--single-line", action = "store_true", help = "single output line per object")
@@ -74,4 +74,4 @@ parser.add_argument("certs", nargs = "+", type = Certificate, help = "RPKI objec
args = parser.parse_args()
for cert in args.certs:
- print cert
+ print cert