diff --git a/cli/cli.go b/cli/cli.go index a923d95..7e9def8 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -87,16 +87,17 @@ func Run(args []string, tty terminal.Terminal) int { }() if *dumpPem { - err = lib.ReadAsPEMFromFiles(files, *dumpType, tty.ReadPassword, func(block *pem.Block) error { + err = lib.ReadAsPEMFromFiles(files, *dumpType, tty.ReadPassword, func(block *pem.Block, format string) error { block.Headers = nil return pem.Encode(stdout, block) }) } else { - err = lib.ReadAsX509FromFiles(files, *dumpType, tty.ReadPassword, func(cert *x509.Certificate, err error) error { + err = lib.ReadAsX509FromFiles(files, *dumpType, tty.ReadPassword, func(cert *x509.Certificate, format string, err error) error { if err != nil { return fmt.Errorf("error parsing block: %s\n", strings.TrimSuffix(err.Error(), "\n")) } else { result.Certificates = append(result.Certificates, cert) + result.Formats = append(result.Formats, format) } return nil }) @@ -107,6 +108,7 @@ func Run(args []string, tty terminal.Terminal) int { } else { for i, cert := range result.Certificates { fmt.Fprintf(stdout, "** CERTIFICATE %d **\n", i+1) + fmt.Fprintf(stdout, "Input Format: %s\n", result.Formats[i]) fmt.Fprintf(stdout, "%s\n\n", lib.EncodeX509ToText(cert, terminalWidth, *verbose)) } } @@ -156,6 +158,7 @@ func Run(args []string, tty terminal.Terminal) int { for i, cert := range result.Certificates { fmt.Fprintf(stdout, "** CERTIFICATE %d **\n", i+1) + fmt.Fprintf(stdout, "Input Format: %s\n", result.Formats[i]) fmt.Fprintf(stdout, "%s\n\n", lib.EncodeX509ToText(cert, terminalWidth, *verbose)) } lib.PrintVerifyResult(stdout, *result.VerifyResult) @@ -176,7 +179,7 @@ func Run(args []string, tty terminal.Terminal) int { defer file.Close() chain := []*x509.Certificate{} - err = lib.ReadAsX509FromFiles([]*os.File{file}, *verifyType, tty.ReadPassword, func(cert *x509.Certificate, err error) error { + err = lib.ReadAsX509FromFiles([]*os.File{file}, *verifyType, tty.ReadPassword, func(cert *x509.Certificate, format string, err error) error { if err != nil { return err } else { diff --git a/cli/cli_test.go b/cli/cli_test.go index f4b7d98..295f328 100644 --- a/cli/cli_test.go +++ b/cli/cli_test.go @@ -42,6 +42,7 @@ t/DtcM/GpAhBbLP9Tk7kPB41v5fRIxVDo50Iz/qvkr37pQ4RsejSFg== ` const expectedVerbose string = `** CERTIFICATE 1 ** +Input Format: PEM Serial: 4096 Valid: 2017-07-19 16:50 UTC to 2017-07-29 16:50 UTC Signature: SHA256-RSA diff --git a/lib/certs.go b/lib/certs.go index fb203fd..f75c5ce 100644 --- a/lib/certs.go +++ b/lib/certs.go @@ -88,7 +88,7 @@ func errorFromErrors(errs []error) error { // data may be in plain-text PEM files, DER-encoded certificates or PKCS7 // envelopes, or PKCS12/JCEKS keystores. All inputs will be converted to PEM // blocks and passed to the callback. -func ReadAsPEMFromFiles(files []*os.File, format string, password func(string) string, callback func(*pem.Block) error) error { +func ReadAsPEMFromFiles(files []*os.File, format string, password func(string) string, callback func(*pem.Block, string) error) error { var errs []error for _, file := range files { reader := bufio.NewReaderSize(file, 4) @@ -109,7 +109,7 @@ func ReadAsPEMFromFiles(files []*os.File, format string, password func(string) s // be in plain-text PEM files, DER-encoded certificates or PKCS7 envelopes, or // PKCS12/JCEKS keystores. All inputs will be converted to PEM blocks and // passed to the callback. -func ReadAsPEM(readers []io.Reader, format string, password func(string) string, callback func(*pem.Block) error) error { +func ReadAsPEM(readers []io.Reader, format string, password func(string) string, callback func(*pem.Block, string) error) error { errs := []error{} for _, r := range readers { reader := bufio.NewReaderSize(r, 4) @@ -130,7 +130,7 @@ func ReadAsPEM(readers []io.Reader, format string, password func(string) string, // inputs. Input data may be in plain-text PEM files, DER-encoded certificates // or PKCS7 envelopes, or PKCS12/JCEKS keystores. All inputs will be converted // to X.509 certificates (private keys are skipped) and passed to the callback. -func ReadAsX509FromFiles(files []*os.File, format string, password func(string) string, callback func(*x509.Certificate, error) error) error { +func ReadAsX509FromFiles(files []*os.File, format string, password func(string) string, callback func(*x509.Certificate, string, error) error) error { errs := []error{} for _, file := range files { reader := bufio.NewReaderSize(file, 4) @@ -151,7 +151,7 @@ func ReadAsX509FromFiles(files []*os.File, format string, password func(string) // data may be in plain-text PEM files, DER-encoded certificates or PKCS7 // envelopes, or PKCS12/JCEKS keystores. All inputs will be converted to X.509 // certificates (private keys are skipped) and passed to the callback. -func ReadAsX509(readers []io.Reader, format string, password func(string) string, callback func(*x509.Certificate, error) error) error { +func ReadAsX509(readers []io.Reader, format string, password func(string) string, callback func(*x509.Certificate, string, error) error) error { errs := []error{} for _, r := range readers { reader := bufio.NewReaderSize(r, 4) @@ -168,20 +168,20 @@ func ReadAsX509(readers []io.Reader, format string, password func(string) string return errorFromErrors(errs) } -func pemToX509(callback func(*x509.Certificate, error) error) func(*pem.Block) error { - return func(block *pem.Block) error { +func pemToX509(callback func(*x509.Certificate, string, error) error) func(*pem.Block, string) error { + return func(block *pem.Block, format string) error { switch block.Type { case "CERTIFICATE": cert, err := x509.ParseCertificate(block.Bytes) - return callback(cert, err) + return callback(cert, format, err) case "PKCS7": certs, err := pkcs7.ExtractCertificates(block.Bytes) if err == nil { for _, cert := range certs { - return callback(cert, nil) + return callback(cert, format, nil) } } else { - return callback(nil, err) + return callback(nil, format, err) } case "CERTIFICATE REQUEST": fmt.Println(red.SprintfFunc()("warning: certificate requests are not supported")) @@ -191,19 +191,20 @@ func pemToX509(callback func(*x509.Certificate, error) error) func(*pem.Block) e } // readCertsFromStream takes some input and converts it to PEM blocks. -func readCertsFromStream(reader io.Reader, filename string, format string, password func(string) string, callback func(*pem.Block) error) error { +func readCertsFromStream(reader io.Reader, filename string, format string, password func(string) string, callback func(*pem.Block, string) error) error { headers := map[string]string{} if filename != "" && filename != os.Stdin.Name() { headers[fileHeader] = filename } - switch strings.TrimSpace(format) { + format = strings.TrimSpace(format) + switch format { case "PEM": scanner := pemScanner(reader) for scanner.Scan() { block, _ := pem.Decode(scanner.Bytes()) block.Headers = mergeHeaders(block.Headers, headers) - err := callback(block) + err := callback(block, format) if err != nil { return err } @@ -217,7 +218,7 @@ func readCertsFromStream(reader io.Reader, filename string, format string, passw x509Certs, err0 := x509.ParseCertificates(data) if err0 == nil { for _, cert := range x509Certs { - err := callback(EncodeX509ToPEM(cert, headers)) + err := callback(EncodeX509ToPEM(cert, headers), format) if err != nil { return err } @@ -227,7 +228,7 @@ func readCertsFromStream(reader io.Reader, filename string, format string, passw p7bBlocks, err1 := pkcs7.ParseSignedData(data) if err1 == nil { for _, block := range p7bBlocks { - err := callback(pkcs7ToPem(block, headers)) + err := callback(pkcs7ToPem(block, headers), format) if err != nil { return err } @@ -246,7 +247,7 @@ func readCertsFromStream(reader io.Reader, filename string, format string, passw } for _, block := range blocks { block.Headers = mergeHeaders(block.Headers, headers) - err := callback(block) + err := callback(block, format) if err != nil { return err } @@ -259,7 +260,7 @@ func readCertsFromStream(reader io.Reader, filename string, format string, passw } for _, alias := range keyStore.ListCerts() { cert, _ := keyStore.GetCert(alias) - err := callback(EncodeX509ToPEM(cert, mergeHeaders(headers, map[string]string{nameHeader: alias}))) + err := callback(EncodeX509ToPEM(cert, mergeHeaders(headers, map[string]string{nameHeader: alias})), format) if err != nil { return err } @@ -277,12 +278,12 @@ func readCertsFromStream(reader io.Reader, filename string, format string, passw return fmt.Errorf("problem reading key: %s\n", err) } - if err := callback(block); err != nil { + if err := callback(block, format); err != nil { return err } for _, cert := range certs { - if err = callback(EncodeX509ToPEM(cert, mergedHeaders)); err != nil { + if err = callback(EncodeX509ToPEM(cert, mergedHeaders), format); err != nil { return err } } diff --git a/lib/verify.go b/lib/verify.go index c4635a7..8587a5b 100644 --- a/lib/verify.go +++ b/lib/verify.go @@ -47,6 +47,7 @@ type SimpleVerification struct { type SimpleResult struct { Certificates []*x509.Certificate `json:"certificates"` + Formats []string VerifyResult *SimpleVerification `json:"verify_result,omitempty"` TLSConnectionState *tls.ConnectionState CertificateRequestInfo *tls.CertificateRequestInfo @@ -94,7 +95,7 @@ func caBundle(caPath string) (*x509.CertPool, error) { // TODO: The JDK trust store ships with this password. return "changeit" }, - func(cert *x509.Certificate, err error) error { + func(cert *x509.Certificate, format string, err error) error { if err != nil { return fmt.Errorf("error parsing CA bundle: %s\n", err) } else { diff --git a/tests/dump-cert-chain-to-text.t b/tests/dump-cert-chain-to-text.t index da669c8..94cf5f4 100644 --- a/tests/dump-cert-chain-to-text.t +++ b/tests/dump-cert-chain-to-text.t @@ -109,6 +109,7 @@ Dump a live cert chain (squareup-chain.crt) $ certigo --verbose dump squareup-chain.crt ** CERTIFICATE 1 ** + Input Format: PEM Serial: 260680855742043049380997676879525498489 Valid: 2016-07-15 20:15 UTC to 2017-07-31 20:45 UTC Signature: SHA256-RSA @@ -148,6 +149,7 @@ Dump a live cert chain (squareup-chain.crt) \tgosq.co, www.gosq.co (esc) ** CERTIFICATE 2 ** + Input Format: PEM Serial: 30215777750102225331854468774 Valid: 2014-12-15 15:25 UTC to 2030-10-15 15:55 UTC Signature: SHA256-RSA @@ -176,6 +178,7 @@ Dump a live cert chain (squareup-chain.crt) \tServer Auth (esc) ** CERTIFICATE 3 ** + Input Format: PEM Serial: 1372799044 Valid: 2014-09-22 17:14 UTC to 2024-09-23 01:31 UTC Signature: SHA256-RSA diff --git a/tests/dump-leaf-to-not-verbose.t b/tests/dump-leaf-to-not-verbose.t index 6962d30..06cefe8 100644 --- a/tests/dump-leaf-to-not-verbose.t +++ b/tests/dump-leaf-to-not-verbose.t @@ -28,6 +28,7 @@ Dump an example certificate (example-leaf.crt) $ certigo dump example-leaf.crt ** CERTIFICATE 1 ** + Input Format: PEM Valid: 2016-06-10 22:14 UTC to 2023-04-15 22:14 UTC Subject: \tC=US, ST=CA, O=certigo, OU=example, CN=example-leaf (esc) diff --git a/tests/dump-leaf-to-text.t b/tests/dump-leaf-to-text.t index 1324280..a47a1cc 100644 --- a/tests/dump-leaf-to-text.t +++ b/tests/dump-leaf-to-text.t @@ -28,6 +28,7 @@ Dump an example certificate (example-leaf.crt) $ certigo --verbose dump example-leaf.crt ** CERTIFICATE 1 ** + Input Format: PEM Serial: 15384458167827828543 Valid: 2016-06-10 22:14 UTC to 2023-04-15 22:14 UTC Signature: SHA256-RSA diff --git a/tests/dump-name-constraints-to-text.t b/tests/dump-name-constraints-to-text.t index 171a1a7..7f1f6da 100644 --- a/tests/dump-name-constraints-to-text.t +++ b/tests/dump-name-constraints-to-text.t @@ -55,6 +55,7 @@ Dump an example certificate with name constraints (example-name-constraints.crt) $ certigo --verbose dump example-name-constraints.crt ** CERTIFICATE 1 ** + Input Format: PEM Serial: 13776854720312847553 Valid: 2017-08-18 19:48 UTC to 2024-06-22 19:48 UTC Signature: SHA256-RSA (self-signed) @@ -88,6 +89,7 @@ Dump an example certificate with name constraints (example-name-constraints.crt) \tCert Sign (esc) ** CERTIFICATE 2 ** + Input Format: PEM Serial: 0 Valid: 2011-12-06 13:49 UTC to 2031-12-01 13:49 UTC Signature: SHA1-RSA (self-signed) diff --git a/tests/dump-small-key-to-text.t b/tests/dump-small-key-to-text.t index 7525807..05d95be 100644 --- a/tests/dump-small-key-to-text.t +++ b/tests/dump-small-key-to-text.t @@ -21,6 +21,7 @@ Dump an example certificate (example-leaf.crt) $ certigo --verbose dump example-small-key.crt ** CERTIFICATE 1 ** + Input Format: PEM Serial: 14381893493177441266 Valid: 2016-06-10 22:14 UTC to 2023-04-15 22:14 UTC Signature: SHA256-RSA (self-signed) diff --git a/tests/dump-spiffe-cert-to-text.t b/tests/dump-spiffe-cert-to-text.t index 1df4055..2318740 100644 --- a/tests/dump-spiffe-cert-to-text.t +++ b/tests/dump-spiffe-cert-to-text.t @@ -35,6 +35,7 @@ Dump a SPIFFE example certificate (example-spiffe.crt) $ certigo --verbose dump example-spiffe.crt ** CERTIFICATE 1 ** + Input Format: PEM Serial: 4096 Valid: 2017-07-19 16:50 UTC to 2017-07-29 16:50 UTC Signature: SHA256-RSA