File: cert_util.py

package info (click to toggle)
golang-github-google-certificate-transparency 0.0~git20160709.0.0f6e3d1~ds1-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, buster
  • size: 5,676 kB
  • sloc: cpp: 35,278; python: 11,838; java: 1,911; sh: 1,885; makefile: 950; xml: 520; ansic: 225
file content (140 lines) | stat: -rwxr-xr-x 5,181 bytes parent folder | download
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
#!/usr/bin/env python
"""cert_util.py: X509 certificate parsing utility.

Usage:

  cert_util.py <command> [flags] [cert_file ...]

Known commands:

  print: print information about the certificates in given files

  Each file must contain either one or more PEM-encoded certificates,
  or a single DER certificate.

  For example:

  cert_util.py print cert.pem           - pretty-print the certificate(s)
  cert_util.py print c1.pem c2.pem      - pretty-print certificates from
                                          multiple files
  cert_util.py print cert.der           - both PEM and DER are accepted formats
                                          (use --filetype to force a format)
  cert_util.py print --debug cert.pem   - print full ASN.1 structure
  cert_util.py print --subject cert.pem - print the subject name
  cert_util.py print --issuer cert.pem  - print the issuer name
  cert_util.py print --fingerprint cert.pem
                                        - print the SHA-1 fingerprint
  cert_util.py print --fingerprint --digest="sha256" cert.pem
                                        - print the SHA-256 fingerprint
"""

import sys
from ct.crypto import cert
from ct.crypto import error
from ct.crypto import pem
from ct.crypto.asn1 import print_util
import gflags

FLAGS = gflags.FLAGS
gflags.DEFINE_bool("subject", False, "Print option: prints certificate subject")
gflags.DEFINE_bool("issuer", False, "Print option: prints certificate issuer")
gflags.DEFINE_bool("fingerprint", False, "Print option: prints certificate "
                   "fingerprint")
gflags.DEFINE_string("digest", "sha1", "Print option: fingerprint digest to use")
gflags.DEFINE_bool("debug", False,
                   "Print option: prints full ASN.1 debug information")
gflags.DEFINE_string("filetype", "", "Read option: specify an input file "
                     "format (pem or der). If no format is specified, the "
                     "parser attempts to detect the format automatically.")
gflags.RegisterValidator("filetype", lambda value: not value or
                         value.lower() in {"pem", "der"},
                         message="--filetype must be one of pem or der")


def print_cert(certificate):
    if not FLAGS.subject and not FLAGS.issuer and not FLAGS.fingerprint:
        if FLAGS.debug:
            print "%r" % certificate
        else:
            print certificate
    else:
        if FLAGS.subject:
            print "subject:\n%s" % certificate.print_subject_name()
        if FLAGS.issuer:
            print "issuer:\n%s" % certificate.print_issuer_name()
        if FLAGS.fingerprint:
            # Print in a format familiar from OpenSSL.
            print "%s fingerprint: %s\n" % (
                FLAGS.digest.upper(), print_util.bytes_to_hex(
                    certificate.fingerprint(hashfunc=FLAGS.digest)))


def print_certs(cert_file):
    """Print the certificates, or parts thereof, as specified by flags."""
    # If no format is specified, try PEM first, and automatically fall back
    # to DER. The advantage is that usage is more convenient; the disadvantage
    # is that error messages are less helpful because we don't know the expected
    # file format.
    printed = False
    if not FLAGS.filetype or FLAGS.filetype.lower() == "pem":
        if not FLAGS.filetype:
            print "Attempting to read PEM"

        try:
            for c in cert.certs_from_pem_file(cert_file, strict_der=False):
                print_cert(c)
                printed = True
        except pem.PemError as e:
            if not printed:
                # Immediate error
                print "File is not a valid PEM file: %s" % e
            else:
                exit_with_message("Error while scanning PEM blocks: %s" % e)
        except error.ASN1Error as e:
            exit_with_message("Bad DER encoding: %s" % e)

    if not printed and FLAGS.filetype.lower() != "pem":
        if not FLAGS.filetype:
            print "Attempting to read raw DER"
        try:
            print_cert(cert.Certificate.from_der_file(cert_file,
                                                      strict_der=False))
        except error.ASN1Error as e:
            exit_with_message("Failed to parse DER from %s" % cert_file)


def exit_with_message(error_message):
    print error_message
    print "Use --helpshort or --help to get help."
    sys.exit(1)


def main(argv):
    if len(argv) <= 1 or argv[1][0] == "-":
        # No command. Parse flags anyway to trigger help flags.
        try:
            argv = FLAGS(argv)
            exit_with_message("No command")
        except gflags.FlagsError as e:
            exit_with_message("Error parsing flags: %s" % e)

    argv = argv[1:]

    try:
        argv = FLAGS(argv)
    except gflags.FlagsError as e:
        exit_with_message("Error parsing flags: %s" % e)

    command, argv = argv[0], argv[1:]

    if command != "print":
        exit_with_message("Unknown command %s" % command)

    if not argv:
        exit_with_message("No certificate file given")
    for filename in argv:
        print_certs(filename)
    sys.exit(0)

if __name__ == "__main__":
    main(sys.argv)