From 5de2475749480b927d62874336d8b8ecbff01c29 Mon Sep 17 00:00:00 2001 From: prateeknischal Date: Sat, 25 Jan 2020 15:32:32 +0530 Subject: [PATCH] Add parsing for Certificate Signing Request Add support for parsing a CSR in the --dump flag using a --csr flag. This flag would only read the Certificate Signing Requests in the file. --- README.md | 33 +++++++-- lib/certs.go | 9 +++ lib/display.go | 153 +++++++++++++++++++++++++++++++-------- lib/encoder.go | 94 +++++++++++++++++++++++- lib/tls.go | 6 ++ lib/verify.go | 26 +++++-- main.go | 30 +++++++- tests/dump-csr-to-text.t | 124 +++++++++++++++++++++++++++++++ 8 files changed, 427 insertions(+), 48 deletions(-) create mode 100644 tests/dump-csr-to-text.t diff --git a/README.md b/README.md index 94187d3..754a51a 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Certigo has commands to dump certificates and keystores from a file, to connect ``` usage: certigo [] [ ...] -A command line certificate examination utility. +A command-line utility to examine and validate certificates to help with debugging SSL/TLS issues. Flags: --help Show context-sensitive help (also try --help-long and --help-man). @@ -55,25 +55,29 @@ Commands: dump [] [...] - Display information about a certificate from a file/stdin. + Display information about a certificate from a file or stdin. -f, --format=FORMAT Format of given input (PEM, DER, JCEKS, PKCS12; heuristic if missing). -p, --password=PASSWORD Password for PKCS12/JCEKS key stores (reads from TTY if missing). -m, --pem Write output as PEM blocks instead of human-readable format. -j, --json Write output as machine-readable JSON format. -d, --depth=0 Certificate chain information upto a certain depth. + -c, --csr Parse only Certificate Signing Request(s) in the file(s). - connect [] [] + connect [] [] Connect to a server and print its certificate(s). -n, --name=NAME Override the server name used for Server Name Indication (SNI). --ca=CA Path to CA bundle (system default if unspecified). --cert=CERT Client certificate chain for connecting to server (PEM). --key=KEY Private key for client certificate, if not in same file (PEM). - -t, --start-tls=PROTOCOL Enable StartTLS protocol ('ldap', 'mysql', 'postgres', 'smtp' or 'ftp'). + -t, --start-tls=PROTOCOL Enable StartTLS protocol; one of: [mysql postgres psql smtp ldap ftp imap]. + --identity="certigo" With --start-tls, sets the DB user or SMTP EHLO name + --proxy=PROXY Optional URI for HTTP(s) CONNECT proxy to dial connections with --timeout=5s Timeout for connecting to remote server (can be '5m', '1s', etc). -m, --pem Write output as PEM blocks instead of human-readable format. -j, --json Write output as machine-readable JSON format. + --verify Verify certificate chain. -d, --depth=0 Certificate chain information upto a certain depth. verify --name=NAME [] [] @@ -88,7 +92,7 @@ Commands: ### Examples -Display information about a certificate (also supports `--pem` and `--json` output): +Display information about a certificate (also supports `--pem`, `--depth` and `--json` output): ``` $ certigo dump --verbose squareup-2016.crt @@ -127,6 +131,25 @@ Alternate DNS Names: www.gosq.co ``` +Display information about a certificate signing request (also supports `--depth` and `--json` output) + +``` +$ certigo dump --csr test.csr --verbose +** CERTIFICATE REQUEST 1 ** +Signature: ECDSA-SHA256 +Subject Info: + Country: IN + Province: KA + Locality: Bangalore + Organization: Certigo + Organizational Unit: InfoSec + CommonName: test.certigo.com + Email Address: a@b.c +Warnings: + Certificate Request is not in X509v3 format (version is 0) + Certificate Request doesn't have any valid DNS/URI names or IP addresses set +``` + Display & validate certificates from a remote server (also supports `--start-tls`): ``` diff --git a/lib/certs.go b/lib/certs.go index 0bc70bf..b39cc44 100644 --- a/lib/certs.go +++ b/lib/certs.go @@ -285,6 +285,15 @@ func EncodeX509ToPEM(cert *x509.Certificate, headers map[string]string) *pem.Blo } } +// EncodeX509CSRToPEM converts an X.509 certificate request to a PEM block for output +func EncodeX509CSRToPEM(csr *x509.CertificateRequest, headers map[string]string) *pem.Block { + return &pem.Block{ + Type: "CERTIFICATE REQUEST", + Bytes: csr.Raw, + Headers: headers, + } +} + // Convert a PKCS7 envelope into a PEM block for output. func pkcs7ToPem(block *pkcs7.SignedDataEnvelope, headers map[string]string) *pem.Block { return &pem.Block{ diff --git a/lib/display.go b/lib/display.go index cd54c33..8c94862 100644 --- a/lib/display.go +++ b/lib/display.go @@ -156,6 +156,62 @@ Email Addresses: Warnings:{{range .Warnings}} {{. | redify}}{{end}}{{end}}` +var csrLayout = ` +{{- if .Version}}{{.Version}} +{{end -}} +Subject: + {{wrapWith .Width "\n\t" (.Subject.Name | printShortName)}} +{{- if .AltDNSNames}} +DNS Names: + {{wrapWith .Width "\n\t" (join ", " .AltDNSNames)}}{{end}} +{{- if .AltIPAddresses}} + {{wrapWith .Width "\n\t" (join ", " .AltIPAdresses)}}{{end}} +{{- if .URINames}} +URI Names: + {{wrapWith .Width "\n\t" (join ", " .URINames)}}{{end}} +{{- if .EmailAddresses}} +Email Addresses: + {{wrapWith .Width "\n\t" (join ", " .EmailAddresses)}}{{end}} +{{- if .Warnings}} +Warnings:{{range .Warnings}} + {{. | redify}}{{end}}{{end}}` + +var verboseCSRLayout = ` +{{- define "PkixName" -}} +{{- range .Names}} + {{ .Type | oidName }}: {{ .Value }} +{{- end -}} +{{end -}} + +Signature: {{.SignatureAlgorithm | highlightAlgorithm}} +Subject Info: + {{- template "PkixName" .Subject.Name}} +{{- if .AltDNSNames}} +{{- range .Extensions}} + {{ .Id | oidName}}: {{.Value}} +{{- end -}} +DNS Names: + {{wrapWith .Width "\n\t" (join ", " .AltDNSNames)}} +{{- end}} +{{- if .AltIPAddresses}} +IP Addresses: + {{wrapWith .Width "\n\t" (join ", " .AltIPAddresses)}} +{{- end}} +{{- if .URINames}} +URI Names: + {{wrapWith .Width "\n\t" (join ", " .URINames)}} +{{- end}} +{{- if .EmailAddresses}} +Email Addresses: + {{wrapWith .Width "\n\t" (join ", " .EmailAddresses)}} +{{- end}} +{{- if .Warnings}} +Warnings: +{{- range .Warnings}} + {{. | redify}} +{{- end}} +{{- end}}` + type certWithName struct { name string file string @@ -200,52 +256,91 @@ func EncodeX509ToObject(cert *x509.Certificate) interface{} { } // EncodeX509ToText encodes an X.509 certificate into human-readable text. -func EncodeX509ToText(cert *x509.Certificate, terminalWidth int, verbose bool) []byte { - c := createSimpleCertificate("", cert) - c.Width = terminalWidth - 8 /* Need some margin for tab */ - - return displayCert(c, verbose) +func EncodeX509ToText(obj interface{}, terminalWidth int, verbose bool) []byte { + switch obj.(type) { + case *x509.Certificate: + obj, ok := obj.(*x509.Certificate) + if ok { + c := createSimpleCertificate("", obj) + c.Width = terminalWidth - 8 /* Need some margin for tab */ + return displayCert(c, verbose) + } + case *x509.CertificateRequest: + obj, ok := obj.(*x509.CertificateRequest) + if ok { + c := createSimpleCertificateRequest("", obj) + c.Width = terminalWidth - 8 /* Need some margin for tab */ + return displayCert(c, verbose) + } + } + // should never happen + return nil } // displayCert takes in a parsed certificate object // (for jceks certs, blank otherwise), and prints out relevant // information. Start and end dates are colored based on whether or not // the certificate is expired, not expired, or close to expiring. -func displayCert(cert simpleCertificate, verbose bool) []byte { +func displayCert(obj interface{}, verbose bool) []byte { // Use template functions from sprig, but add some extras funcMap := sprig.TxtFuncMap() + var t *template.Template + var err error - extras := template.FuncMap{ - "certStart": certStart, - "certEnd": certEnd, - "redify": redify, - "highlightAlgorithm": highlightAlgorithm, - "hexify": hexify, - "keyUsage": keyUsage, - "extKeyUsage": extKeyUsage, - "oidName": oidName, - "oidShort": oidShort, - "printShortName": PrintShortName, - "printCommonName": PrintCommonName, - } - for k, v := range extras { - funcMap[k] = v - } + switch obj.(type) { + case simpleCertificate: + extras := template.FuncMap{ + "certStart": certStart, + "certEnd": certEnd, + "redify": redify, + "highlightAlgorithm": highlightAlgorithm, + "hexify": hexify, + "keyUsage": keyUsage, + "extKeyUsage": extKeyUsage, + "oidName": oidName, + "oidShort": oidShort, + "printShortName": PrintShortName, + "printCommonName": PrintCommonName, + } + for k, v := range extras { + funcMap[k] = v + } - t := template.New("Cert template").Funcs(funcMap) - var err error - if verbose { - t, err = t.Parse(verboseLayout) - } else { - t, err = t.Parse(layout) + t = template.New("Cert template").Funcs(funcMap) + if verbose { + t, err = t.Parse(verboseLayout) + } else { + t, err = t.Parse(layout) + } + case simpleCertificateRequest: + extras := template.FuncMap{ + "redify": redify, + "highlightAlgorithm": highlightAlgorithm, + "hexify": hexify, + "oidName": oidName, + "oidShort": oidShort, + "printShortName": PrintShortName, + "printCommonName": PrintCommonName, + } + for k, v := range extras { + funcMap[k] = v + } + + t = template.New("Cert Request template").Funcs(funcMap) + if verbose { + t, err = t.Parse(verboseCSRLayout) + } else { + t, err = t.Parse(csrLayout) + } } + if err != nil { // Should never happen panic(err) } var buffer bytes.Buffer w := bufio.NewWriter(&buffer) - err = t.Execute(w, cert) + err = t.Execute(w, obj) if err != nil { // Should never happen panic(err) diff --git a/lib/encoder.go b/lib/encoder.go index 7794e26..e4169ea 100644 --- a/lib/encoder.go +++ b/lib/encoder.go @@ -207,6 +207,24 @@ type simpleCertificate struct { Width int `json:"-"` } +type simpleCertificateRequest struct { + Version int `json:"version,omitempty"` + SignatureAlgorithm simpleSigAlg `json:"signature_algorithm"` + PublicKeyAlgorithm string `json:"public_key_algorithm"` + Subject simplePKIXName `json:"subject"` + Extensions []pkix.Extension `json:"extensions,omitempty"` + ExtraExtensions []pkix.Extension `json:"extra_extensions,omitempty"` + AltDNSNames []string `json:"dns_names,omitempty"` + EmailAddresses []string `json:"email_addresses,omitempty"` + AltIPAddresses []net.IP `json:"ip_addresses,omitempty"` + URINames []string `json:"uri_names,omitempty"` + Warnings []string `json:"warnings,omitempty"` + PEM string `json:"pem,omitempty"` + + // Internal fields for text display. Set - to skip serialize. + Width int `json:"-"` +} + type simplePKIXName struct { Name pkix.Name KeyID []byte @@ -284,6 +302,32 @@ func createSimpleCertificate(name string, cert *x509.Certificate) simpleCertific return out } +func createSimpleCertificateRequest(name string, csr *x509.CertificateRequest) simpleCertificateRequest { + out := simpleCertificateRequest{ + Version: csr.Version, + SignatureAlgorithm: simpleSigAlg(csr.SignatureAlgorithm), + PublicKeyAlgorithm: csr.PublicKeyAlgorithm.String(), + Subject: simplePKIXName{ + Name: csr.Subject, + KeyID: []byte(csr.Subject.SerialNumber), + }, + Extensions: csr.Extensions, + ExtraExtensions: csr.ExtraExtensions, + AltDNSNames: csr.DNSNames, + EmailAddresses: csr.EmailAddresses, + AltIPAddresses: csr.IPAddresses, + PEM: string(pem.EncodeToMemory(EncodeX509CSRToPEM(csr, nil))), + } + + uriNames := make([]string, len(csr.URIs)) + for i, u := range csr.URIs { + uriNames[i] = u.String() + } + + out.Warnings = csrWarnings(csr, uriNames) + return out +} + func (p simplePKIXName) MarshalJSON() ([]byte, error) { out := map[string]interface{}{} @@ -409,9 +453,52 @@ func certWarnings(cert *x509.Certificate, uriNames []string) (warnings []string) return } +func csrWarnings(csr *x509.CertificateRequest, uriNames []string) (warnings []string) { + if csr.CheckSignature() != nil { + warnings = append(warnings, "Signature on this appears to be invalid") + } + + if csr.Version < 2 { + warnings = append(warnings, fmt.Sprintf("Certificate Request is not in X509v3 format (version is %d)", csr.Version)) + } + + if len(csr.DNSNames) == 0 && len(csr.IPAddresses) == 0 && len(uriNames) == 0 { + warnings = append(warnings, fmt.Sprintf("Certificate Request doesn't have any valid DNS/URI names or IP addresses set")) + } + + warnings = append(warnings, algWarnings(csr)...) + + return +} + // algWarnings checks key sizes, signature algorithms. -func algWarnings(cert *x509.Certificate) (warnings []string) { - alg, size := decodeKey(cert.PublicKey) +func algWarnings(obj interface{}) (warnings []string) { + var alg string + var size int + var signatureAlg x509.SignatureAlgorithm + var key *rsa.PublicKey + + switch obj.(type) { + case *x509.Certificate: + cert, _ := obj.(*x509.Certificate) + alg, size = decodeKey(cert.PublicKey) + signatureAlg = cert.SignatureAlgorithm + + if alg == "RSA" { + key = cert.PublicKey.(*rsa.PublicKey) + } + + case *x509.CertificateRequest: + csr, _ := obj.(*x509.CertificateRequest) + alg, size = decodeKey(csr.PublicKey) + signatureAlg = csr.SignatureAlgorithm + + if alg == "RSA" { + key = csr.PublicKey.(*rsa.PublicKey) + } + } + + // alg, size := decodeKey(cert.PublicKey) if (alg == "RSA" || alg == "DSA") && size < 2048 { warnings = append(warnings, fmt.Sprintf("Size of %s key should be at least 2048 bits", alg)) } @@ -420,13 +507,12 @@ func algWarnings(cert *x509.Certificate) (warnings []string) { } for _, alg := range badSignatureAlgorithms { - if cert.SignatureAlgorithm == alg { + if signatureAlg == alg { warnings = append(warnings, fmt.Sprintf("Signed with %s, which is an outdated signature algorithm", algString(alg))) } } if alg == "RSA" { - key := cert.PublicKey.(*rsa.PublicKey) if key.E < 3 { warnings = append(warnings, "Public key exponent in RSA key is less than 3") } diff --git a/lib/tls.go b/lib/tls.go index f35622b..e19ad19 100644 --- a/lib/tls.go +++ b/lib/tls.go @@ -4,6 +4,7 @@ import ( "bufio" "bytes" "crypto/tls" + "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "fmt" @@ -128,6 +129,11 @@ func EncodeCRIToObject(cri *tls.CertificateRequestInfo) (interface{}, error) { return out, nil } +// EncodeCSRToObject returns a JSON-marshallable representation of a Certificate Request object +func EncodeCSRToObject(csr *x509.CertificateRequest) interface{} { + return createSimpleCertificateRequest("", csr) +} + // Just a map lookup with a default func lookup(descriptions map[uint16]description, what uint16) description { v, ok := descriptions[what] diff --git a/lib/verify.go b/lib/verify.go index 0a33303..8950bb3 100644 --- a/lib/verify.go +++ b/lib/verify.go @@ -46,20 +46,22 @@ type SimpleVerification struct { } type SimpleResult struct { - Certificates []*x509.Certificate `json:"certificates"` - VerifyResult *SimpleVerification `json:"verify_result,omitempty"` + Certificates []*x509.Certificate `json:"certificates"` + CertificateRequests []*x509.CertificateRequest `json:"certificate_requests"` + VerifyResult *SimpleVerification `json:"verify_result,omitempty"` TLSConnectionState *tls.ConnectionState CertificateRequestInfo *tls.CertificateRequestInfo } func (s SimpleResult) MarshalJSON() ([]byte, error) { - certs := make([]interface{}, len(s.Certificates)) - for i, c := range s.Certificates { - certs[i] = EncodeX509ToObject(c) - } - out := map[string]interface{}{} - out["certificates"] = certs + if s.Certificates != nil { + certs := make([]interface{}, len(s.Certificates)) + for i, c := range s.Certificates { + certs[i] = EncodeX509ToObject(c) + } + out["certificates"] = certs + } if s.VerifyResult != nil { out["verify_result"] = s.VerifyResult } @@ -73,6 +75,14 @@ func (s SimpleResult) MarshalJSON() ([]byte, error) { } out["certificate_request_info"] = encoded } + if s.CertificateRequests != nil { + csrs := make([]interface{}, len(s.CertificateRequests)) + for i, c := range s.CertificateRequests { + csrs[i] = EncodeCSRToObject(c) + } + + out["certificate_requests"] = csrs + } return json.Marshal(out) } diff --git a/main.go b/main.go index 5c02e10..25c02c8 100644 --- a/main.go +++ b/main.go @@ -42,6 +42,7 @@ var ( dumpPem = dump.Flag("pem", "Write output as PEM blocks instead of human-readable format.").Short('m').Bool() dumpJSON = dump.Flag("json", "Write output as machine-readable JSON format.").Short('j').Bool() dumpDepth = dump.Flag("depth", "Certificate chain information upto a certain depth.").Short('d').Default("0").Int() + dumpCsr = dump.Flag("csr", "Parse only Certificate Signing Request(s) in the file(s).").Short('c').Bool() connect = app.Command("connect", "Connect to a server and print its certificate(s).") connectTo = connect.Arg("server[:port]", "Hostname or IP to connect to, with optional port.").String() @@ -97,6 +98,31 @@ func main() { block.Headers = nil pem.Encode(os.Stdout, block) }) + } else if *dumpCsr { + err = lib.ReadAsPEMFromFiles(files, *dumpType, nil, func(block *pem.Block) { + certReq, err := x509.ParseCertificateRequest(block.Bytes) + if err != nil { + return + } + + result.CertificateRequests = append(result.CertificateRequests, certReq) + }) + + csrCount := len(result.CertificateRequests) + if csrCount > *dumpDepth && *dumpDepth > 0 { + csrCount = *dumpDepth + } + + if *dumpJSON { + result.CertificateRequests = result.CertificateRequests[:csrCount] + blob, _ := json.Marshal(result) + fmt.Println(string(blob)) + } else { + for i, csr := range result.CertificateRequests[:csrCount] { + fmt.Fprintf(stdout, "** CERTIFICATE REQUEST %d **\n", i+1) + fmt.Fprintf(stdout, "%s\n\n", lib.EncodeX509ToText(csr, terminalWidth, *verbose)) + } + } } else { err = lib.ReadAsX509FromFiles(files, *dumpType, readPassword, func(cert *x509.Certificate, err error) { if err != nil { @@ -129,8 +155,8 @@ func main() { if err != nil { fmt.Fprintf(os.Stderr, "error: %s\n", strings.TrimSuffix(err.Error(), "\n")) os.Exit(1) - } else if len(result.Certificates) == 0 && !*dumpPem { - fmt.Fprintf(os.Stderr, "warning: no certificates found in input\n") + } else if len(result.Certificates) == 0 && !*dumpPem && len(result.CertificateRequests) == 0 { + fmt.Fprintf(os.Stderr, "warning: no certificates or requests found in input\n") } case connect.FullCommand(): // Get certs by connecting to a server diff --git a/tests/dump-csr-to-text.t b/tests/dump-csr-to-text.t new file mode 100644 index 0000000..5f190b3 --- /dev/null +++ b/tests/dump-csr-to-text.t @@ -0,0 +1,124 @@ +Set up test data. + + $ cat > ec-req.pem < -----BEGIN CERTIFICATE REQUEST----- + > MIIBPzCB5gIBADCBgzELMAkGA1UEBhMCSU4xCzAJBgNVBAgMAktBMRIwEAYDVQQH + > DAlCYW5nYWxvcmUxEDAOBgNVBAoMB0NlcnRpZ28xEDAOBgNVBAsMB0luZm9TZWMx + > GTAXBgNVBAMMEHRlc3QuY2VydGlnby5jb20xFDASBgkqhkiG9w0BCQEWBWFAYi5j + > MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEt434uInYNO41D/otGSIRGhzlUWW3 + > uiZqstGh7Tf47hKgXX7Mnq3iukPv6Zpoy72SrOVrNJBsv4gsYYLScjhgF6AAMAoG + > CCqGSM49BAMCA0gAMEUCIH8plgdk1nT3GaVM9u/FwQbrFNkFnj9Nr1fAGLc6XNFY + > AiEAoqtThEy7IvRLtQG0ZBnaaBlReyygpyMxSJPniciKONs= + > -----END CERTIFICATE REQUEST----- + > EOF + + $ certigo --verbose dump --csr ec-req.pem + ** CERTIFICATE REQUEST 1 ** + Signature: ECDSA-SHA256 + Subject Info: + \tCountry: IN (esc) + \tProvince: KA (esc) + \tLocality: Bangalore (esc) + \tOrganization: Certigo (esc) + \tOrganizational Unit: InfoSec (esc) + \tCommonName: test.certigo.com (esc) + \tEmail Address: a@b.c (esc) + Warnings: + \tCertificate Request is not in X509v3 format (version is 0) (esc) + \tCertificate Request doesn't have any valid DNS/URI names or IP addresses set (esc) + +Testing with normal certs + $ cat > example-sha1.csr< -----BEGIN CERTIFICATE REQUEST----- + > MIICmjCCAYICAQAwVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQK + > EwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxlLXNo + > YTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCUuAbvyfPJsBEr41hy + > eAX26jhZJWVbioCveouRbgfO9JQOdHxKRNJtWiI2+rVwUfIRxF9qO/wsNeRDHjsb + > W5KD4prsp8RNLZJqVKm171XwCCUSDeiHTUJfTzsMiV2PwwbzQOK41m0uywtrhEUL + > cW9+Z+UZ7wnE6+NlU9aLNGEZ94hh3BsnKip/pGHGsIh14vaXE4M+OTJvXkUs/6/d + > L2yBdiZiw9bqv1GIU3vliI5h28tjB118duwf7ZMqxoRQ32wsUmskNMN/S0OLoS/9 + > BTNyGH2vG/juZnt//Wh35563cun2Qp0va8WzNTRrqRtULfn/+5CwaswnutervIu9 + > 9xnxAgMBAAGgADANBgkqhkiG9w0BAQUFAAOCAQEAECEYs5iOXzghMNgRB0bCgCKA + > Gw8hfiDCZ1qJLei+ozK8lndbWmXnqDBKPUQnNrLcMHRIrqL1h1nS2wDXJjRn8Tdk + > CyvGGWpTfN2weOtcxoOs/kQLN5AJWfOhmPmBoImAt9CJw5zRL1d7CRU/+DoZY3Fr + > FTZM8hHPghL5O838535sqerwIGFtkX6LkFG/gkz6JzZHI1fusEx73FpgNj3UaBZ4 + > zOlEkbtOAABq8RVGNXZ5DJQLCTsu0p9w6jsgcYs3PYNyFoW1RMUcTvDEWCExLLr4 + > m0syZsTfgBNuhaCUNr97BNHR0t1Uy1AnSACZpYdwi254gp0nL5673/CYbZT38A== + > -----END CERTIFICATE REQUEST----- + > EOF + + $ certigo --verbose dump --csr example-sha1.csr + ** CERTIFICATE REQUEST 1 ** + Signature: SHA1-RSA + Subject Info: + \tCountry: US (esc) + \tProvince: CA (esc) + \tOrganization: certigo (esc) + \tOrganizational Unit: example (esc) + \tCommonName: example-sha1 (esc) + Warnings: + \tCertificate Request is not in X509v3 format (version is 0) (esc) + \tCertificate Request doesn't have any valid DNS/URI names or IP addresses set (esc) + \tSigned with SHA1-RSA, which is an outdated signature algorithm (esc) + +Testing JSON dump + $ cat > example-root.csr< -----BEGIN CERTIFICATE REQUEST----- + > MIICmjCCAYICAQAwVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQK + > EwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxlLXJv + > b3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKOEoSiNjMQ8/zUFcQ + > W89LWw+UeTXKGwNDSpGjyi8jBKZ1lWPbnMmrjI6DZ9ReevHHzqBdKZt+9NFPFEz7 + > djDMRByIuJhRvzhfFBflaIdSeNk2+NpUaFuUUUd6IIePu0AdRveJ8ZGHXRwCeEDI + > VCZS4oBYPHOhX/zMWDg8vSO4pSxTjGc7I8fHxaUSkVzUBbeO9T/1eFk0m2uxs3Uz + > iUck2X/8YqRd+p/EaBED78nXvKRALAguKAzqxIgk3ccPK0SVQFNFq+eV1/qo8cou + > eQuqMpCAvwVkfpVKhneyC2NlMrfzlcZZbfG/irlSjQn5+ExZX4Isy1pCUbOiVfSr + > sCdtAgMBAAGgADANBgkqhkiG9w0BAQUFAAOCAQEAoDcBLidVU6KA9IlID32P3uox + > fjKsbJee6mswMBqkFKqgdv/vHMiXAttiVxB+Y5AQnkb+kMCl8KwVaXgH145drahz + > 0aTH6Rxqrf+1OfStQ+Y1CZgRL26vpafvd3xFE7151upO+dUraiYt9736umoStuqX + > WuqV9EZ5RmvhqEW6cIa6zG5KVlHgDs72jC1f+7nAsj3V3EBqwf/NtOMz+whFo3LB + > DJU4djTjLiROa/bWI1ZvhKjFf6EWQnZIeGhZLyS8Y+0qoiI1ojhrOYYAdOOHGTV5 + > RJqViMG2o7YxaMYA/QCaYVmkiTlfwR9fZrZOG4lHZ6PyTLtwkHYXkmCgUW237w== + > -----END CERTIFICATE REQUEST----- + > EOF + + $ certigo dump --csr example-root.csr --json + {"certificate_requests":[{"signature_algorithm":"SHA1-RSA","public_key_algorithm":"RSA","subject":{"common_name":"example-root","country":["US"],"organization":["certigo"],"organizational_unit":["example"],"province":["CA"]},"warnings":["Certificate Request is not in X509v3 format (version is 0)","Certificate Request doesn't have any valid DNS/URI names or IP addresses set","Signed with SHA1-RSA, which is an outdated signature algorithm"],"pem":"-----BEGIN CERTIFICATE REQUEST-----\nMIICmjCCAYICAQAwVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQK\nEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxlLXJv\nb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKOEoSiNjMQ8/zUFcQ\nW89LWw+UeTXKGwNDSpGjyi8jBKZ1lWPbnMmrjI6DZ9ReevHHzqBdKZt+9NFPFEz7\ndjDMRByIuJhRvzhfFBflaIdSeNk2+NpUaFuUUUd6IIePu0AdRveJ8ZGHXRwCeEDI\nVCZS4oBYPHOhX/zMWDg8vSO4pSxTjGc7I8fHxaUSkVzUBbeO9T/1eFk0m2uxs3Uz\niUck2X/8YqRd+p/EaBED78nXvKRALAguKAzqxIgk3ccPK0SVQFNFq+eV1/qo8cou\neQuqMpCAvwVkfpVKhneyC2NlMrfzlcZZbfG/irlSjQn5+ExZX4Isy1pCUbOiVfSr\nsCdtAgMBAAGgADANBgkqhkiG9w0BAQUFAAOCAQEAoDcBLidVU6KA9IlID32P3uox\nfjKsbJee6mswMBqkFKqgdv/vHMiXAttiVxB+Y5AQnkb+kMCl8KwVaXgH145drahz\n0aTH6Rxqrf+1OfStQ+Y1CZgRL26vpafvd3xFE7151upO+dUraiYt9736umoStuqX\nWuqV9EZ5RmvhqEW6cIa6zG5KVlHgDs72jC1f+7nAsj3V3EBqwf/NtOMz+whFo3LB\nDJU4djTjLiROa/bWI1ZvhKjFf6EWQnZIeGhZLyS8Y+0qoiI1ojhrOYYAdOOHGTV5\nRJqViMG2o7YxaMYA/QCaYVmkiTlfwR9fZrZOG4lHZ6PyTLtwkHYXkmCgUW237w==\n-----END CERTIFICATE REQUEST-----\n"}]} + +Testing depth flag + $ cat > test.csr< -----BEGIN CERTIFICATE REQUEST----- + > MIIBPzCB5gIBADCBgzELMAkGA1UEBhMCSU4xCzAJBgNVBAgMAktBMRIwEAYDVQQH + > DAlCYW5nYWxvcmUxEDAOBgNVBAoMB0NlcnRpZ28xEDAOBgNVBAsMB0luZm9TZWMx + > GTAXBgNVBAMMEHRlc3QuY2VydGlnby5jb20xFDASBgkqhkiG9w0BCQEWBWFAYi5j + > MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEt434uInYNO41D/otGSIRGhzlUWW3 + > uiZqstGh7Tf47hKgXX7Mnq3iukPv6Zpoy72SrOVrNJBsv4gsYYLScjhgF6AAMAoG + > CCqGSM49BAMCA0gAMEUCIH8plgdk1nT3GaVM9u/FwQbrFNkFnj9Nr1fAGLc6XNFY + > AiEAoqtThEy7IvRLtQG0ZBnaaBlReyygpyMxSJPniciKONs= + > -----END CERTIFICATE REQUEST----- + > -----BEGIN CERTIFICATE REQUEST----- + > MIICmjCCAYICAQAwVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQK + > EwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxlLXJv + > b3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKOEoSiNjMQ8/zUFcQ + > W89LWw+UeTXKGwNDSpGjyi8jBKZ1lWPbnMmrjI6DZ9ReevHHzqBdKZt+9NFPFEz7 + > djDMRByIuJhRvzhfFBflaIdSeNk2+NpUaFuUUUd6IIePu0AdRveJ8ZGHXRwCeEDI + > VCZS4oBYPHOhX/zMWDg8vSO4pSxTjGc7I8fHxaUSkVzUBbeO9T/1eFk0m2uxs3Uz + > iUck2X/8YqRd+p/EaBED78nXvKRALAguKAzqxIgk3ccPK0SVQFNFq+eV1/qo8cou + > eQuqMpCAvwVkfpVKhneyC2NlMrfzlcZZbfG/irlSjQn5+ExZX4Isy1pCUbOiVfSr + > sCdtAgMBAAGgADANBgkqhkiG9w0BAQUFAAOCAQEAoDcBLidVU6KA9IlID32P3uox + > fjKsbJee6mswMBqkFKqgdv/vHMiXAttiVxB+Y5AQnkb+kMCl8KwVaXgH145drahz + > 0aTH6Rxqrf+1OfStQ+Y1CZgRL26vpafvd3xFE7151upO+dUraiYt9736umoStuqX + > WuqV9EZ5RmvhqEW6cIa6zG5KVlHgDs72jC1f+7nAsj3V3EBqwf/NtOMz+whFo3LB + > DJU4djTjLiROa/bWI1ZvhKjFf6EWQnZIeGhZLyS8Y+0qoiI1ojhrOYYAdOOHGTV5 + > RJqViMG2o7YxaMYA/QCaYVmkiTlfwR9fZrZOG4lHZ6PyTLtwkHYXkmCgUW237w== + > -----END CERTIFICATE REQUEST----- + > EOF + + $ certigo dump --depth 1 --csr test.csr + ** CERTIFICATE REQUEST 1 ** + Subject: + \tC=IN, ST=KA, L=Bangalore, O=Certigo, OU=InfoSec, (esc) + \tCN=test.certigo.com (esc) + Warnings: + \tCertificate Request is not in X509v3 format (version is 0) (esc) + \tCertificate Request doesn't have any valid DNS/URI names or IP addresses set (esc) + \ No newline at end of file