diff --git a/api/openapi.gen.go b/api/openapi.gen.go index 24078b2..3d841b3 100644 --- a/api/openapi.gen.go +++ b/api/openapi.gen.go @@ -107,8 +107,8 @@ type Client struct { // Relationships Values used as parameters when referencing related resources. Relationships struct { - Organization *RelationshipsOrganizationSlug `json:"organization,omitempty"` - Service *RelationshipsServiceSlug `json:"service,omitempty"` + Organization RelationshipsOrganizationSlug `json:"organization"` + Service RelationshipsServiceSlug `json:"service"` } `json:"relationships"` // Slug A value used as a parameter when referencing this client. @@ -392,11 +392,11 @@ type CreateCliTokenJSONBody struct { // CreateClientJSONBody defines parameters for CreateClient. type CreateClientJSONBody struct { - Relationships *struct { - Organization *RelationshipsOrganizationSlug `json:"organization,omitempty"` - Service *RelationshipsServiceSlug `json:"service,omitempty"` - } `json:"relationships,omitempty"` - ServerType *string `json:"server_type,omitempty"` + Relationships struct { + Organization RelationshipsOrganizationSlug `json:"organization"` + Service RelationshipsServiceSlug `json:"service"` + } `json:"relationships"` + ServerType string `json:"server_type"` Type *string `json:"type,omitempty"` } diff --git a/lcl/clean.go b/lcl/clean.go index 06ee9dc..10cb153 100644 --- a/lcl/clean.go +++ b/lcl/clean.go @@ -55,8 +55,8 @@ func (c LclClean) run(ctx context.Context, drv *ui.Driver) error { cmd := &trust.Clean{ Anc: c.anc, - OrgSlug: orgAPID, - RealmSlug: realmAPID, + OrgAPID: orgAPID, + RealmAPID: realmAPID, } err = cmd.Perform(ctx, drv) diff --git a/service/env.go b/service/env.go index a7e946f..83d4b77 100644 --- a/service/env.go +++ b/service/env.go @@ -14,6 +14,7 @@ import ( "github.com/anchordotdev/cli/auth" "github.com/anchordotdev/cli/clipboard" "github.com/anchordotdev/cli/component" + componentmodels "github.com/anchordotdev/cli/component/models" "github.com/anchordotdev/cli/service/models" "github.com/anchordotdev/cli/ui" ) @@ -273,7 +274,14 @@ func (c *Env) orgAPID(ctx context.Context, cfg *cli.Config, drv *ui.Driver) (str return c.OrgAPID, nil } if cfg.Org.APID != "" { - return cfg.Org.APID, nil + drv.Activate(ctx, &componentmodels.ConfigVia{ + Config: cfg, + ConfigFetchFn: func(cfg *cli.Config) any { return cfg.Org.APID }, + Flag: "--org", + Singular: "organization", + }) + c.OrgAPID = cfg.Org.APID + return c.OrgAPID, nil } selector := &component.Selector[api.Organization]{ @@ -297,7 +305,14 @@ func (c *Env) realmAPID(ctx context.Context, cfg *cli.Config, drv *ui.Driver, or return c.RealmAPID, nil } if cfg.Realm.APID != "" { - return cfg.Realm.APID, nil + drv.Activate(ctx, &componentmodels.ConfigVia{ + Config: cfg, + ConfigFetchFn: func(cfg *cli.Config) any { return cfg.Realm.APID }, + Flag: "--realm", + Singular: "realm", + }) + c.RealmAPID = cfg.Realm.APID + return c.RealmAPID, nil } selector := &component.Selector[api.Realm]{ @@ -321,7 +336,14 @@ func (c *Env) serviceAPID(ctx context.Context, cfg *cli.Config, drv *ui.Driver, return c.ServiceAPID, nil } if cfg.Service.APID != "" { - return cfg.Service.APID, nil + drv.Activate(ctx, &componentmodels.ConfigVia{ + Config: cfg, + ConfigFetchFn: func(cfg *cli.Config) any { return cfg.Service.APID }, + Flag: "--service", + Singular: "service", + }) + c.ServiceAPID = cfg.Service.APID + return c.ServiceAPID, nil } selector := &component.Selector[api.Service]{ diff --git a/trust/audit.go b/trust/audit.go index 2a86f12..c46338b 100644 --- a/trust/audit.go +++ b/trust/audit.go @@ -2,12 +2,15 @@ package trust import ( "context" + "fmt" "github.com/spf13/cobra" "github.com/anchordotdev/cli" "github.com/anchordotdev/cli/api" "github.com/anchordotdev/cli/auth" + "github.com/anchordotdev/cli/component" + componentmodels "github.com/anchordotdev/cli/component/models" "github.com/anchordotdev/cli/trust/models" "github.com/anchordotdev/cli/truststore" truststoremodels "github.com/anchordotdev/cli/truststore/models" @@ -25,7 +28,9 @@ var CmdTrustAudit = cli.NewCmd[Audit](CmdTrust, "audit", func(cmd *cobra.Command }) type Audit struct { - anc *api.Session + Anc *api.Session + + OrgAPID, RealmAPID string } func (a Audit) UI() cli.UI { @@ -35,12 +40,14 @@ func (a Audit) UI() cli.UI { } func (c *Audit) RunTUI(ctx context.Context, drv *ui.Driver) error { + cfg := cli.ConfigFromContext(ctx) + var err error cmd := &auth.Client{ - Anc: c.anc, + Anc: c.Anc, Source: "lclhost", } - c.anc, err = cmd.Perform(ctx, drv) + c.Anc, err = cmd.Perform(ctx, drv) if err != nil { return err } @@ -48,14 +55,19 @@ func (c *Audit) RunTUI(ctx context.Context, drv *ui.Driver) error { drv.Activate(ctx, models.TrustAuditHeader) drv.Activate(ctx, models.TrustAuditHint) - drv.Activate(ctx, &truststoremodels.TrustStoreAudit{}) + orgAPID, err := c.orgAPID(ctx, cfg, drv) + if err != nil { + return err + } - org, realm, err := fetchOrgAndRealm(ctx, c.anc) + realmAPID, err := c.realmAPID(ctx, cfg, drv, orgAPID) if err != nil { return err } - expectedCAs, err := FetchExpectedCAs(ctx, c.anc, org, realm) + drv.Activate(ctx, &truststoremodels.TrustStoreAudit{}) + + expectedCAs, err := FetchExpectedCAs(ctx, c.Anc, orgAPID, realmAPID) if err != nil { return err } @@ -85,3 +97,65 @@ func (c *Audit) RunTUI(ctx context.Context, drv *ui.Driver) error { return nil } + +func (c *Audit) orgAPID(ctx context.Context, cfg *cli.Config, drv *ui.Driver) (string, error) { + if c.OrgAPID != "" { + return c.OrgAPID, nil + } + if cfg.Org.APID != "" { + drv.Activate(ctx, &componentmodels.ConfigVia{ + Config: cfg, + ConfigFetchFn: func(cfg *cli.Config) any { return cfg.Org.APID }, + Flag: "--org", + Singular: "organization", + }) + c.OrgAPID = cfg.Org.APID + return c.OrgAPID, nil + } + + selector := &component.Selector[api.Organization]{ + Prompt: "Which organization's env do you want to fetch?", + Flag: "--org", + + Fetcher: &component.Fetcher[api.Organization]{ + FetchFn: func() ([]api.Organization, error) { return c.Anc.GetOrgs(ctx) }, + }, + } + + org, err := selector.Choice(ctx, drv) + if err != nil { + return "", err + } + return org.Apid, nil +} + +func (c *Audit) realmAPID(ctx context.Context, cfg *cli.Config, drv *ui.Driver, orgAPID string) (string, error) { + if c.RealmAPID != "" { + return c.RealmAPID, nil + } + if cfg.Realm.APID != "" { + drv.Activate(ctx, &componentmodels.ConfigVia{ + Config: cfg, + ConfigFetchFn: func(cfg *cli.Config) any { return cfg.Realm.APID }, + Flag: "--realm", + Singular: "realm", + }) + c.RealmAPID = cfg.Realm.APID + return c.RealmAPID, nil + } + + selector := &component.Selector[api.Realm]{ + Prompt: fmt.Sprintf("Which %s realm's env do you want to fetch?", ui.Emphasize(orgAPID)), + Flag: "--realm", + + Fetcher: &component.Fetcher[api.Realm]{ + FetchFn: func() ([]api.Realm, error) { return c.Anc.GetOrgRealms(ctx, orgAPID) }, + }, + } + + realm, err := selector.Choice(ctx, drv) + if err != nil { + return "", err + } + return realm.Apid, nil +} diff --git a/trust/audit_test.go b/trust/audit_test.go index b48eae0..04d1298 100644 --- a/trust/audit_test.go +++ b/trust/audit_test.go @@ -80,12 +80,14 @@ func TestAudit(t *testing.T) { t.Fatal(err) } - org, realm, err := fetchOrgAndRealm(ctx, anc) + userInfo, err := anc.UserInfo(ctx) if err != nil { t.Fatal(err) } + orgAPID := userInfo.PersonalOrg.Slug + realmAPID := "localhost" - expectedCAs, err := FetchExpectedCAs(ctx, anc, org, realm) + expectedCAs, err := FetchExpectedCAs(ctx, anc, orgAPID, realmAPID) if err != nil { t.Fatal(err) } diff --git a/trust/clean.go b/trust/clean.go index 3948b71..847dd23 100644 --- a/trust/clean.go +++ b/trust/clean.go @@ -9,6 +9,8 @@ import ( "github.com/anchordotdev/cli" "github.com/anchordotdev/cli/api" "github.com/anchordotdev/cli/auth" + "github.com/anchordotdev/cli/component" + componentmodels "github.com/anchordotdev/cli/component/models" "github.com/anchordotdev/cli/trust/models" "github.com/anchordotdev/cli/truststore" "github.com/anchordotdev/cli/ui" @@ -31,7 +33,7 @@ var CmdTrustClean = cli.NewCmd[Clean](CmdTrust, "clean", func(cmd *cobra.Command type Clean struct { Anc *api.Session - OrgSlug, RealmSlug string + OrgAPID, RealmAPID string } func (c Clean) UI() cli.UI { @@ -66,20 +68,22 @@ func (c *Clean) runTUI(ctx context.Context, drv *ui.Driver) error { return nil } -func (c Clean) Perform(ctx context.Context, drv *ui.Driver) error { +func (c *Clean) Perform(ctx context.Context, drv *ui.Driver) error { cfg := cli.ConfigFromContext(ctx) - var err error - if c.OrgSlug == "" && c.RealmSlug == "" { - c.OrgSlug, c.RealmSlug, err = fetchOrgAndRealm(ctx, c.Anc) - if err != nil { - return err - } + orgAPID, err := c.orgAPID(ctx, cfg, drv) + if err != nil { + return err + } + + realmAPID, err := c.realmAPID(ctx, cfg, drv, orgAPID) + if err != nil { + return err } drv.Activate(ctx, &models.TrustCleanAudit{}) - expectedCAs, err := FetchExpectedCAs(ctx, c.Anc, c.OrgSlug, c.RealmSlug) + expectedCAs, err := FetchExpectedCAs(ctx, c.Anc, orgAPID, realmAPID) if err != nil { return err } @@ -164,3 +168,65 @@ func classifyError(err error) error { return err } } + +func (c *Clean) orgAPID(ctx context.Context, cfg *cli.Config, drv *ui.Driver) (string, error) { + if c.OrgAPID != "" { + return c.OrgAPID, nil + } + if cfg.Org.APID != "" { + drv.Activate(ctx, &componentmodels.ConfigVia{ + Config: cfg, + ConfigFetchFn: func(cfg *cli.Config) any { return cfg.Org.APID }, + Flag: "--org", + Singular: "organization", + }) + c.OrgAPID = cfg.Org.APID + return c.OrgAPID, nil + } + + selector := &component.Selector[api.Organization]{ + Prompt: "Which organization's env do you want to fetch?", + Flag: "--org", + + Fetcher: &component.Fetcher[api.Organization]{ + FetchFn: func() ([]api.Organization, error) { return c.Anc.GetOrgs(ctx) }, + }, + } + + org, err := selector.Choice(ctx, drv) + if err != nil { + return "", err + } + return org.Apid, nil +} + +func (c *Clean) realmAPID(ctx context.Context, cfg *cli.Config, drv *ui.Driver, orgAPID string) (string, error) { + if c.RealmAPID != "" { + return c.RealmAPID, nil + } + if cfg.Realm.APID != "" { + drv.Activate(ctx, &componentmodels.ConfigVia{ + Config: cfg, + ConfigFetchFn: func(cfg *cli.Config) any { return cfg.Realm.APID }, + Flag: "--realm", + Singular: "realm", + }) + c.RealmAPID = cfg.Realm.APID + return c.RealmAPID, nil + } + + selector := &component.Selector[api.Realm]{ + Prompt: fmt.Sprintf("Which %s realm's env do you want to fetch?", ui.Emphasize(orgAPID)), + Flag: "--realm", + + Fetcher: &component.Fetcher[api.Realm]{ + FetchFn: func() ([]api.Realm, error) { return c.Anc.GetOrgRealms(ctx, orgAPID) }, + }, + } + + realm, err := selector.Choice(ctx, drv) + if err != nil { + return "", err + } + return realm.Apid, nil +} diff --git a/trust/testdata/TestAudit/expected,_missing,_and_extra_CAs.golden b/trust/testdata/TestAudit/expected,_missing,_and_extra_CAs.golden index 3091c60..f7d83fb 100644 --- a/trust/testdata/TestAudit/expected,_missing,_and_extra_CAs.golden +++ b/trust/testdata/TestAudit/expected,_missing,_and_extra_CAs.golden @@ -9,20 +9,48 @@ # Audit CA Certificates in Your Local Trust Store(s) `anchor trust audit` | We'll compare your CA certificates from Anchor and your local trust stores. +─── Fetcher[github.com/anchordotdev/cli/api.Organization] ────────────────────── + +# Audit CA Certificates in Your Local Trust Store(s) `anchor trust audit` + | We'll compare your CA certificates from Anchor and your local trust stores. + * Fetching organizations…⠋ +─── Fetcher[github.com/anchordotdev/cli/api.Organization] ────────────────────── + +# Audit CA Certificates in Your Local Trust Store(s) `anchor trust audit` + | We'll compare your CA certificates from Anchor and your local trust stores. + - Using org-slug, the only available organization. You can also use `--org org-slug`. +─── Fetcher[github.com/anchordotdev/cli/api.Realm] ───────────────────────────── + +# Audit CA Certificates in Your Local Trust Store(s) `anchor trust audit` + | We'll compare your CA certificates from Anchor and your local trust stores. + - Using org-slug, the only available organization. You can also use `--org org-slug`. + * Fetching realms…⠋ +─── Fetcher[github.com/anchordotdev/cli/api.Realm] ───────────────────────────── + +# Audit CA Certificates in Your Local Trust Store(s) `anchor trust audit` + | We'll compare your CA certificates from Anchor and your local trust stores. + - Using org-slug, the only available organization. You can also use `--org org-slug`. + - Using realm-slug, the only available realm. You can also use `--realm realm-slug`. ─── TrustStoreAudit ──────────────────────────────────────────────────────────── # Audit CA Certificates in Your Local Trust Store(s) `anchor trust audit` | We'll compare your CA certificates from Anchor and your local trust stores. + - Using org-slug, the only available organization. You can also use `--org org-slug`. + - Using realm-slug, the only available realm. You can also use `--realm realm-slug`. * Comparing local and expected CA certificates…⠋ ─── TrustStoreAudit ──────────────────────────────────────────────────────────── # Audit CA Certificates in Your Local Trust Store(s) `anchor trust audit` | We'll compare your CA certificates from Anchor and your local trust stores. + - Using org-slug, the only available organization. You can also use `--org org-slug`. + - Using realm-slug, the only available realm. You can also use `--realm realm-slug`. - Compared local and expected CA certificates: need to install 1 missing certificates. ─── TrustAuditInfo ───────────────────────────────────────────────────────────── # Audit CA Certificates in Your Local Trust Store(s) `anchor trust audit` | We'll compare your CA certificates from Anchor and your local trust stores. + - Using org-slug, the only available organization. You can also use `--org org-slug`. + - Using realm-slug, the only available realm. You can also use `--realm realm-slug`. - Compared local and expected CA certificates: need to install 1 missing certificates. - VALID - oas-examples - AnchorCA ECDSA: trusted by [Mock] - MISSING - oas-examples - AnchorCA RSA: missing from [Mock] diff --git a/trust/testdata/TestClean/basics.golden b/trust/testdata/TestClean/basics.golden index 8e54395..e4a0b3e 100644 --- a/trust/testdata/TestClean/basics.golden +++ b/trust/testdata/TestClean/basics.golden @@ -9,13 +9,39 @@ # Clean CA Certificates from Local Trust Store(s) `anchor trust clean` | We'll remove CA certificates from the mock store(s). +─── Fetcher[github.com/anchordotdev/cli/api.Organization] ────────────────────── + +# Clean CA Certificates from Local Trust Store(s) `anchor trust clean` +| We'll remove CA certificates from the mock store(s). + * Fetching organizations…⠋ +─── Fetcher[github.com/anchordotdev/cli/api.Organization] ────────────────────── + +# Clean CA Certificates from Local Trust Store(s) `anchor trust clean` +| We'll remove CA certificates from the mock store(s). + - Using org-slug, the only available organization. You can also use `--org org-slug`. +─── Fetcher[github.com/anchordotdev/cli/api.Realm] ───────────────────────────── + +# Clean CA Certificates from Local Trust Store(s) `anchor trust clean` +| We'll remove CA certificates from the mock store(s). + - Using org-slug, the only available organization. You can also use `--org org-slug`. + * Fetching realms…⠋ +─── Fetcher[github.com/anchordotdev/cli/api.Realm] ───────────────────────────── + +# Clean CA Certificates from Local Trust Store(s) `anchor trust clean` +| We'll remove CA certificates from the mock store(s). + - Using org-slug, the only available organization. You can also use `--org org-slug`. + - Using realm-slug, the only available realm. You can also use `--realm realm-slug`. ─── TrustCleanAudit ──────────────────────────────────────────────────────────── # Clean CA Certificates from Local Trust Store(s) `anchor trust clean` | We'll remove CA certificates from the mock store(s). + - Using org-slug, the only available organization. You can also use `--org org-slug`. + - Using realm-slug, the only available realm. You can also use `--realm realm-slug`. * Auditing local CA certificates…⠋ ─── TrustCleanAudit ──────────────────────────────────────────────────────────── # Clean CA Certificates from Local Trust Store(s) `anchor trust clean` | We'll remove CA certificates from the mock store(s). + - Using org-slug, the only available organization. You can also use `--org org-slug`. + - Using realm-slug, the only available realm. You can also use `--realm realm-slug`. - Audited local CA certificates: need to remove 0 certificates. diff --git a/trust/trust.go b/trust/trust.go index 57c03cd..13f3051 100644 --- a/trust/trust.go +++ b/trust/trust.go @@ -4,7 +4,6 @@ import ( "context" "crypto/x509" "encoding/pem" - "errors" "fmt" "log" "os" @@ -15,6 +14,7 @@ import ( "github.com/anchordotdev/cli/api" "github.com/anchordotdev/cli/auth" "github.com/anchordotdev/cli/component" + componentmodels "github.com/anchordotdev/cli/component/models" "github.com/anchordotdev/cli/ext509" "github.com/anchordotdev/cli/ext509/oid" "github.com/anchordotdev/cli/trust/models" @@ -37,7 +37,7 @@ var CmdTrust = cli.NewCmd[Command](cli.CmdRoot, "trust", func(cmd *cobra.Command type Command struct { Anc *api.Session - OrgSlug, RealmSlug string + OrgAPID, RealmAPID string AuditInfo *truststore.AuditInfo } @@ -135,19 +135,19 @@ func (c *Command) Perform(ctx context.Context, drv *ui.Driver) error { } func (c *Command) performAudit(ctx context.Context, cfg *cli.Config, drv *ui.Driver, stores []truststore.Store) (*truststore.AuditInfo, error) { - orgSlug, err := c.orgSlug(ctx, cfg, drv) + orgAPID, err := c.orgAPID(ctx, cfg, drv) if err != nil { return nil, err } - realmSlug, err := c.realmSlug(ctx, cfg, drv, orgSlug) + realmAPID, err := c.realmAPID(ctx, cfg, drv, orgAPID) if err != nil { return nil, err } drv.Activate(ctx, &truststoremodels.TrustStoreAudit{}) - cas, err := FetchExpectedCAs(ctx, c.Anc, orgSlug, realmSlug) + cas, err := FetchExpectedCAs(ctx, c.Anc, orgAPID, realmAPID) if err != nil { return nil, err } @@ -162,12 +162,19 @@ func (c *Command) performAudit(ctx context.Context, cfg *cli.Config, drv *ui.Dri return auditInfo, nil } -func (c *Command) orgSlug(ctx context.Context, cfg *cli.Config, drv *ui.Driver) (string, error) { - if c.OrgSlug != "" { - return c.OrgSlug, nil +func (c *Command) orgAPID(ctx context.Context, cfg *cli.Config, drv *ui.Driver) (string, error) { + if c.OrgAPID != "" { + return c.OrgAPID, nil } if cfg.Org.APID != "" { - return cfg.Org.APID, nil + drv.Activate(ctx, &componentmodels.ConfigVia{ + Config: cfg, + ConfigFetchFn: func(cfg *cli.Config) any { return cfg.Org.APID }, + Flag: "--org", + Singular: "organization", + }) + c.OrgAPID = cfg.Org.APID + return c.OrgAPID, nil } selector := &component.Selector[api.Organization]{ @@ -186,21 +193,28 @@ func (c *Command) orgSlug(ctx context.Context, cfg *cli.Config, drv *ui.Driver) return org.Apid, nil } -func (c *Command) realmSlug(ctx context.Context, cfg *cli.Config, drv *ui.Driver, orgSlug string) (string, error) { - if c.RealmSlug != "" { - return c.RealmSlug, nil +func (c *Command) realmAPID(ctx context.Context, cfg *cli.Config, drv *ui.Driver, orgAPID string) (string, error) { + if c.RealmAPID != "" { + return c.RealmAPID, nil } if cfg.Realm.APID != "" { - return cfg.Realm.APID, nil + drv.Activate(ctx, &componentmodels.ConfigVia{ + Config: cfg, + ConfigFetchFn: func(cfg *cli.Config) any { return cfg.Realm.APID }, + Flag: "--realm", + Singular: "realm", + }) + c.RealmAPID = cfg.Realm.APID + return c.RealmAPID, nil } selector := &component.Selector[api.Realm]{ - Prompt: fmt.Sprintf("Which %s realm do you want to trust?", ui.Emphasize(orgSlug)), + Prompt: fmt.Sprintf("Which %s realm do you want to trust?", ui.Emphasize(orgAPID)), Flag: "--realm", Fetcher: &component.Fetcher[api.Realm]{ - FetchFn: func() ([]api.Realm, error) { return c.Anc.GetOrgRealms(ctx, orgSlug) }, + FetchFn: func() ([]api.Realm, error) { return c.Anc.GetOrgRealms(ctx, orgAPID) }, }, } @@ -211,29 +225,6 @@ func (c *Command) realmSlug(ctx context.Context, cfg *cli.Config, drv *ui.Driver return realm.Apid, nil } -// TODO: Replace with selectors -func fetchOrgAndRealm(ctx context.Context, anc *api.Session) (string, string, error) { - cfg := cli.ConfigFromContext(ctx) - - org, realm := cfg.Org.APID, cfg.Realm.APID - if (org == "") != (realm == "") { - return "", "", errors.New("--org and --realm flags must both be present or absent") - } - if org == "" && realm == "" { - userInfo, err := anc.UserInfo(ctx) - if err != nil { - return "", "", err - } - org = userInfo.PersonalOrg.Slug - - // TODO: use personal org's default realm value from API check-in call, - // instead of hard-coding "localhost" here - realm = "localhost" - } - - return org, realm, nil -} - func PerformAudit(ctx context.Context, stores []truststore.Store, cas []*truststore.CA) (*truststore.AuditInfo, error) { audit := &truststore.Audit{ Expected: cas, diff --git a/truststore/platform.go b/truststore/platform.go index 25f4361..e631ddd 100644 --- a/truststore/platform.go +++ b/truststore/platform.go @@ -99,10 +99,12 @@ func (s *Platform) UninstallCA(ca *CA) (uninstalled bool, err error) { func parseCertificate(der []byte) (*x509.Certificate, error) { cert, err := x509.ParseCertificate(der) if err != nil { - // https://www.alvestrand.no/objectid/2.5.29.37.html if strings.HasPrefix(err.Error(), "x509: certificate contains duplicate extension") { return nil, nil } + if strings.HasPrefix(err.Error(), "x509: inner and outer signature algorithm identifiers don't match") { + return nil, nil + } return nil, err } return cert, nil diff --git a/truststore/platform_test.go b/truststore/platform_test.go index 4a70c57..d2e298c 100644 --- a/truststore/platform_test.go +++ b/truststore/platform_test.go @@ -1,12 +1,13 @@ package truststore import ( - "encoding/hex" + "crypto/x509" + "encoding/pem" + "errors" + "reflect" "testing" ) -var dupExtensionData = "3082032c30820214a003020102020448966180300d06092a864886f70d01010b0500303b311f301d06035504030c16636f6d2e6170706c652e6b65726265726f732e6b646331183016060355040a0c0f53797374656d204964656e74697479301e170d3136313232313232333831395a170d3336313231363232333831395a303b311f301d06035504030c16636f6d2e6170706c652e6b65726265726f732e6b646331183016060355040a0c0f53797374656d204964656e7469747930820122300d06092a864886f70d01010105000382010f003082010a0282010100b0f8a02b7b3fce0c70b96dc22322190b31ee1dd3a80bc4e99cf4d375c86ddb3d2a7a23fee439cdba7fbd18b6dbcaea5a0fa44c86453c72c82ed17a900b8be4ed0ba21a05cc2b4d04cb55f1cd0f46b4ca364b7d34d315397be81615741a0fd536ba2a1d3ffae7c08e952f14e1a8ddf112d0946d685ca5b8efe7147d861aec303a5e6bdfe091102bf68a925c6c7c98965a4fea8012d4b2b9f66d94623feb966cc3e0ac7d3443704aea1a3815ec83be2542c5f925880f03f513bf64df8d52cec3acb29dc81fc227be9d37785e98719caa5e74559f89875978c2503f3170e3b19bb6306b7d6f05c0a4d06c2a28b00105a50e9cc286b3292cedec8092f49f33babe450203010001a3383036300b0603551d0f0404030205a030130603551d25040c300a06082b0601050507030130120603551d25040b300906072b060105020305300d06092a864886f70d01010b0500038201010079ef266b9f73eb58c66e71d71f39ccb6973b61da260666f350d9836799f5375bd5268bc2aeecf5655404770da15022cf7db9e8e5beb8ef2eb60bc88864940d5f8721a58c32451d955c7803b4a87039823774a7de59e25fb4e0da8a3dc755e0f8d23374525fd2e25a27a2cc91dece5a1e807b56d8e50f55ed77f0873638040d0747b4ff414aea1fc1f7ab1872c92fc19176c673a48ce1498a68798943c87a6b533a2ddae91770481cdf253b4ef5b490fa519d9262404345c1dd11093c870b0f3ed0206f1c4575f8c859e3687c3490cd76672be55ebb20664aee9bfd333415809e9fcc11e4cf273b25ef916ed82faa3bb21131e8ab3f8fc97faf925b2dc1c57373" - func TestParseCertificate(t *testing.T) { cert, err := parseCertificate(validCA.Raw) if err != nil { @@ -15,19 +16,77 @@ func TestParseCertificate(t *testing.T) { if cert == nil { t.Fatal("expect parse certificate with valid certificate to return certificate") } + } -func TestParseCertificateDupExtension(t *testing.T) { - dupExtensionBytes, err := hex.DecodeString(dupExtensionData) - if err != nil { - t.Fatal(err) - } +func TestParseInvalidCerts(t *testing.T) { + tests := []struct { + name string + + data string - cert, err := parseCertificate(dupExtensionBytes) - if cert != nil { - t.Fatal("expect parsing duplicate extension certificates to return nil certificate") + cert *x509.Certificate + err error + }{ + { + name: "duplicate-extension", + + data: dupExtensionData, + }, + { + name: "inner-outer-signature-mismatch", + + data: signatureMismatchData, + }, } - if err != nil { - t.Fatal("expect parsing duplicate extension certificate to return nil error") + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + blk, _ := pem.Decode([]byte(test.data)) + cert, err := parseCertificate(blk.Bytes) + if want, got := test.cert, cert; !reflect.DeepEqual(want, got) { + t.Errorf("expect parsed certificate %+v, got %+v", want, got) + } + if want, got := test.err, err; !errors.Is(want, got) { + t.Errorf("expect err %s, got %s", want, got) + } + }) } } + +var ( + dupExtensionData = `-----BEGIN CERTIFICATE----- +MIIDLDCCAhSgAwIBAgIESJZhgDANBgkqhkiG9w0BAQsFADA7MR8wHQYDVQQDDBZj +b20uYXBwbGUua2VyYmVyb3Mua2RjMRgwFgYDVQQKDA9TeXN0ZW0gSWRlbnRpdHkw +HhcNMTYxMjIxMjIzODE5WhcNMzYxMjE2MjIzODE5WjA7MR8wHQYDVQQDDBZjb20u +YXBwbGUua2VyYmVyb3Mua2RjMRgwFgYDVQQKDA9TeXN0ZW0gSWRlbnRpdHkwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCw+KArez/ODHC5bcIjIhkLMe4d +06gLxOmc9NN1yG3bPSp6I/7kOc26f70YttvK6loPpEyGRTxyyC7RepALi+TtC6Ia +BcwrTQTLVfHND0a0yjZLfTTTFTl76BYVdBoP1Ta6Kh0/+ufAjpUvFOGo3fES0JRt +aFyluO/nFH2GGuwwOl5r3+CRECv2ipJcbHyYllpP6oAS1LK59m2UYj/rlmzD4Kx9 +NENwSuoaOBXsg74lQsX5JYgPA/UTv2TfjVLOw6yyncgfwie+nTd4XphxnKpedFWf +iYdZeMJQPzFw47GbtjBrfW8FwKTQbCoosAEFpQ6cwoazKSzt7ICS9J8zur5FAgMB +AAGjODA2MAsGA1UdDwQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATASBgNVHSUE +CzAJBgcrBgEFAgMFMA0GCSqGSIb3DQEBCwUAA4IBAQB57yZrn3PrWMZucdcfOcy2 +lzth2iYGZvNQ2YNnmfU3W9Umi8Ku7PVlVAR3DaFQIs99uejlvrjvLrYLyIhklA1f +hyGljDJFHZVceAO0qHA5gjd0p95Z4l+04NqKPcdV4PjSM3RSX9LiWieizJHezloe +gHtW2OUPVe138Ic2OAQNB0e0/0FK6h/B96sYcskvwZF2xnOkjOFJimh5iUPIemtT +Oi3a6RdwSBzfJTtO9bSQ+lGdkmJAQ0XB3REJPIcLDz7QIG8cRXX4yFnjaHw0kM12 +ZyvlXrsgZkrum/0zNBWAnp/MEeTPJzsl75Fu2C+qO7IRMeirP4/Jf6+SWy3BxXNz +-----END CERTIFICATE-----` + signatureMismatchData = `-----BEGIN CERTIFICATE----- +MIICFDCCAX2gAwIBAgIECZcijjALBgkqhkiG9w0BAQUwPDEgMB4GA1UEAwwXY29t +LmFwcGxlLnN5c3RlbWRlZmF1bHQxGDAWBgNVBAoMD1N5c3RlbSBJZGVudGl0eTAe +Fw0xNTAzMjUyMTEwMjZaFw0zNTAzMjAyMTEwMjZaMDwxIDAeBgNVBAMMF2NvbS5h +cHBsZS5zeXN0ZW1kZWZhdWx0MRgwFgYDVQQKDA9TeXN0ZW0gSWRlbnRpdHkwgZ8w +DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALonEb9P9qvj1BiLCQp86oLkVC+riuqd +llz1JJEtbr2BFEAa/j0CH+FptthLizHSWsVdHN+CrPZUa1rCgVlkuz14huzSPrQG +UjNjpJVDBmlr/T+ALmHewmykM9Sa3yOETVr8q49odjisfcIHLwS+ivymLDgU3mPJ +Qss2jW+Av6lRAgMBAAGjJTAjMAsGA1UdDwQEAwIEsDAUBgNVHSUEDTALBgkqhkiG +92NkBAQwDQYJKoZIhvcNAQEFBQADgYEAroEWpwSHikgb1zjueWPdXwY4o+W+zFqY +uVbrTzd+Tv8SIfgw8+D4Hf9iLLY33yy6CIMZY2xgfGgBh0suSidoLJt3Pr0fiQGK +d5IUuavJmM5HeYXlPfg/WxvtcwaB1DlPxGpe3ZsRi2GPBZpxVS1AdwKUk5GmoH4G +J1hlJQKJ8yY= +-----END CERTIFICATE----- +` +)