From 3fa99e85962d9ab4a90fef66331210894c818d1a Mon Sep 17 00:00:00 2001 From: "peter.reisinger" Date: Thu, 3 Oct 2024 09:25:18 +0100 Subject: [PATCH] add issuer and subject like flags --- README.md | 7 +++++++ flag.go | 14 ++++++++++++++ go.mod | 2 +- go.sum | 4 ++-- main.go | 6 ++++++ pkg/cert/cert.go | 20 ++++++++++++++++++++ pkg/cert/location.go | 26 ++++++++++++++++++++++++++ vendor/modules.txt | 2 +- 8 files changed, 77 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 08eead8..60560d1 100644 --- a/README.md +++ b/README.md @@ -24,11 +24,13 @@ certinfo [flags] [| ...] | -clipboard | read input from clipboard (only if the clipboard is supported) | | -expiry | print expiry of certificates | | -insecure | whether a client verifies the server's certificate chain and host name (only applicable for host) | +| -issuer-like | print certificates with subject field containing supplied string | | -no-duplicate | do not print duplicate certificates | | -no-expired | do not print expired certificates | | -pem | whether to print pem as well | | -pem-only | whether to print only pem (useful for downloading certs from host) | | -sort-expiry | sort certificates by expiration date | +| -subject-like | print certificates with issuer field containing supplied string | | -version | certinfo version | | -help | help | +---------------+---------------------------------------------------------------------------------------------------+ @@ -146,6 +148,11 @@ Subject: CN=GTS Root R1,O=Google Trust Services LLC,C=US Expiry: 4 years 10 months 17 days 4 hours 29 minutes ``` +### show certificate with specific subject +This example shows AWS RDS certificates for specific region (we can also see AWS for 100 years expiration) +- show only eu-west-2 certs `curl https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem | certinfo -issuer-like eu-west-2` +- download only eu-west-2 certs `curl https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem | certinfo -issuer-like eu-west-2 -pem-only > rds-eu-west-2.pem` + ### local root certs - linux `ls -d /etc/ssl/certs/* | grep '.pem' | xargs certinfo -expiry` diff --git a/flag.go b/flag.go index d3eda30..90d2150 100644 --- a/flag.go +++ b/flag.go @@ -15,6 +15,8 @@ type Flags struct { NoDuplicate bool NoExpired bool SortExpiry bool + SubjectLike string + IssuerLike string Insecure bool Chains bool Pem bool @@ -36,6 +38,10 @@ func ParseFlags() (Flags, error) { "do not print expired certificates") flagSet.BoolVar(&flags.SortExpiry, "sort-expiry", getBoolEnv("CERTINFO_SORT_EXPIRY", false), "sort certificates by expiration date") + flagSet.StringVar(&flags.SubjectLike, "subject-like", getStringEnv("CERTINFO_SUBJECT_LIKE", ""), + "print certificates with issuer field containing supplied string") + flagSet.StringVar(&flags.IssuerLike, "issuer-like", getStringEnv("CERTINFO_ISSUER_LIKE", ""), + "print certificates with subject field containing supplied string") flagSet.BoolVar(&flags.Insecure, "insecure", getBoolEnv("CERTINFO_INSECURE", false), "whether a client verifies the server's certificate chain and host name (only applicable for host)") flagSet.BoolVar(&flags.Chains, "chains", getBoolEnv("CERTINFO_CHAINS", false), @@ -64,6 +70,14 @@ func ParseFlags() (Flags, error) { return flags, nil } +func getStringEnv(envName string, defaultValue string) string { + + if env, ok := os.LookupEnv(envName); ok { + return env + } + return defaultValue +} + func getBoolEnv(envName string, defaultValue bool) bool { env, ok := os.LookupEnv(envName) diff --git a/go.mod b/go.mod index b3f38d8..452fbe1 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/exp/shiny v0.0.0-20240909161429-701f63a606c0 // indirect golang.org/x/image v0.20.0 // indirect - golang.org/x/mobile v0.0.0-20240909163608-642950227fb3 // indirect + golang.org/x/mobile v0.0.0-20240930194658-c6794c95c70b // indirect golang.org/x/sys v0.25.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 4e57f2b..e817038 100644 --- a/go.sum +++ b/go.sum @@ -12,8 +12,8 @@ golang.org/x/exp/shiny v0.0.0-20240909161429-701f63a606c0 h1:J0D+bkvD51EjdYYhLL7 golang.org/x/exp/shiny v0.0.0-20240909161429-701f63a606c0/go.mod h1:3F+MieQB7dRYLTmnncoFbb1crS5lfQoTfDgQy6K4N0o= golang.org/x/image v0.20.0 h1:7cVCUjQwfL18gyBJOmYvptfSHS8Fb3YUDtfLIZ7Nbpw= golang.org/x/image v0.20.0/go.mod h1:0a88To4CYVBAHp5FXJm8o7QbUl37Vd85ply1vyD8auM= -golang.org/x/mobile v0.0.0-20240909163608-642950227fb3 h1:HOa20LMHFElnLsGI9j8/sxTIHpogkTuHZlyoIjl3kkw= -golang.org/x/mobile v0.0.0-20240909163608-642950227fb3/go.mod h1:5EJr05J3jS1A5hwVNxs4vC0pIRxtWmwM15D1ZxCj93s= +golang.org/x/mobile v0.0.0-20240930194658-c6794c95c70b h1:vxPknApl9Z0hxiwF2MqAC8pI9Vr79/qaUj+6g6GE4gE= +golang.org/x/mobile v0.0.0-20240930194658-c6794c95c70b/go.mod h1:5EJr05J3jS1A5hwVNxs4vC0pIRxtWmwM15D1ZxCj93s= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/main.go b/main.go index 119215c..49f14ed 100644 --- a/main.go +++ b/main.go @@ -31,6 +31,12 @@ func main() { if flags.NoDuplicate { certificatesFiles = certificatesFiles.RemoveDuplicates() } + if flags.SubjectLike != "" { + certificatesFiles = certificatesFiles.SubjectLike(flags.SubjectLike) + } + if flags.IssuerLike != "" { + certificatesFiles = certificatesFiles.IssuerLike(flags.IssuerLike) + } if flags.SortExpiry { certificatesFiles = certificatesFiles.SortByExpiry() } diff --git a/pkg/cert/cert.go b/pkg/cert/cert.go index c2a346c..40c19fd 100644 --- a/pkg/cert/cert.go +++ b/pkg/cert/cert.go @@ -40,6 +40,26 @@ func (c Certificates) RemoveDuplicates() Certificates { return out } +func (c Certificates) SubjectLike(subject string) Certificates { + var out Certificates + for i := range c { + if strings.Contains(c[i].SubjectString(), subject) { + out = append(out, c[i]) + } + } + return out +} + +func (c Certificates) IssuerLike(issuer string) Certificates { + var out Certificates + for i := range c { + if strings.Contains(c[i].x509Certificate.Issuer.String(), issuer) { + out = append(out, c[i]) + } + } + return out +} + func (c Certificates) SortByExpiry() Certificates { slices.SortFunc(c, func(a, b Certificate) int { return a.x509Certificate.NotAfter.Compare(b.x509Certificate.NotAfter) diff --git a/pkg/cert/location.go b/pkg/cert/location.go index f19e4f8..d401410 100644 --- a/pkg/cert/location.go +++ b/pkg/cert/location.go @@ -33,6 +33,22 @@ func (c CertificateLocations) RemoveDuplicates() CertificateLocations { return out } +func (c CertificateLocations) SubjectLike(subject string) CertificateLocations { + var out CertificateLocations + for i := range c { + out = append(out, c[i].SubjectLike(subject)) + } + return out +} + +func (c CertificateLocations) IssuerLike(issuer string) CertificateLocations { + var out CertificateLocations + for i := range c { + out = append(out, c[i].IssuerLike(issuer)) + } + return out +} + func (c CertificateLocations) SortByExpiry() CertificateLocations { var out CertificateLocations // sort certificates in every location @@ -78,6 +94,16 @@ func (c CertificateLocation) RemoveDuplicates() CertificateLocation { return c } +func (c CertificateLocation) SubjectLike(subject string) CertificateLocation { + c.Certificates = c.Certificates.SubjectLike(subject) + return c +} + +func (c CertificateLocation) IssuerLike(issuer string) CertificateLocation { + c.Certificates = c.Certificates.IssuerLike(issuer) + return c +} + func (c CertificateLocation) SortByExpiry() CertificateLocation { c.Certificates = c.Certificates.SortByExpiry() return c diff --git a/vendor/modules.txt b/vendor/modules.txt index 0403f10..2f70d81 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -28,7 +28,7 @@ golang.org/x/exp/shiny/screen ## explicit; go 1.18 golang.org/x/image/bmp golang.org/x/image/math/f64 -# golang.org/x/mobile v0.0.0-20240909163608-642950227fb3 +# golang.org/x/mobile v0.0.0-20240930194658-c6794c95c70b ## explicit; go 1.22.0 golang.org/x/mobile/app golang.org/x/mobile/app/internal/callfn