forked from ratify-project/ratify
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Support more trust store types (ratify-project#1538)
Signed-off-by: Juncheng Zhu <[email protected]> Co-authored-by: Binbin Li <[email protected]>
- Loading branch information
Showing
7 changed files
with
340 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/* | ||
Copyright The Ratify Authors. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package notation | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/notaryproject/notation-go/verifier/truststore" | ||
) | ||
|
||
// certStores is an interface that defines the methods for managing certificate stores. | ||
type certStores interface { | ||
// GetCertGroup returns certain type of cert group from namedStore | ||
GetCertGroup(ctx context.Context, storeType truststore.Type, namedStore string) (certGroup []string) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
/* | ||
Copyright The Ratify Authors. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package notation | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/notaryproject/notation-go/verifier/truststore" | ||
"github.com/ratify-project/ratify/internal/logger" | ||
) | ||
|
||
type certStoreType string | ||
|
||
const ( | ||
CA certStoreType = "CA" | ||
SigningAuthority certStoreType = "signingAuthority" | ||
) | ||
|
||
func (certstoretype certStoreType) String() string { | ||
return string(certstoretype) | ||
} | ||
|
||
// verificationCertStores describes the configuration of verification certStores | ||
// type verificationCertStores supports new format map[string]map[string][]string | ||
// | ||
// { | ||
// "ca": { | ||
// "certs": {"kv1", "kv2"}, | ||
// }, | ||
// "signingauthority": { | ||
// "certs": {"kv3"} | ||
// }, | ||
// } | ||
// | ||
// type verificationCertStores supports legacy format map[string][]string as well. | ||
// | ||
// { | ||
// "certs": {"kv1", "kv2"}, | ||
// }, | ||
type verificationCertStores map[string]interface{} | ||
|
||
// certStoresByType implements certStores interface and place certs under the trustStoreType | ||
// | ||
// { | ||
// "ca": { | ||
// "certs": {"kv1", "kv2"}, | ||
// }, | ||
// "signingauthority": { | ||
// "certs": {"kv3"} | ||
// }, | ||
// } | ||
type certStoresByType map[certStoreType]map[string][]string | ||
|
||
// newCertStoreByType performs type assertion and converts certificate stores configuration into certStoresByType | ||
func newCertStoreByType(confInNewFormat verificationCertStores) (certStores, error) { | ||
s := make(certStoresByType) | ||
for certstoretype, storeData := range confInNewFormat { | ||
s[certStoreType(certstoretype)] = make(map[string][]string) | ||
parsedStoreData, ok := storeData.(verificationCertStores) | ||
if !ok { | ||
return nil, fmt.Errorf("certStores: %s assertion to type verificationCertStores failed", storeData) | ||
} | ||
for storeName, certProviderList := range parsedStoreData { | ||
var certProviderNames []string | ||
parsedCertProviders, ok := certProviderList.([]interface{}) | ||
if !ok { | ||
return nil, fmt.Errorf("certProviderList: %s assertion to type []interface{} failed", certProviderList) | ||
} | ||
for _, certProvider := range parsedCertProviders { | ||
certProviderName, ok := certProvider.(string) | ||
if !ok { | ||
return nil, fmt.Errorf("certProvider: %s assertion to type string failed", certProvider) | ||
} | ||
certProviderNames = append(certProviderNames, certProviderName) | ||
} | ||
s[certStoreType(certstoretype)][storeName] = certProviderNames | ||
} | ||
} | ||
return s, nil | ||
} | ||
|
||
// GetCertGroup returns certain type of certs from namedStore | ||
func (s certStoresByType) GetCertGroup(ctx context.Context, storeType truststore.Type, namedStore string) (certGroup []string) { | ||
if certStores, ok := s[certStoreType(storeType)]; ok { | ||
if certGroup, ok = certStores[namedStore]; ok { | ||
return | ||
} | ||
} | ||
logger.GetLogger(ctx, logOpt).Warnf("unable to fetch certGroup from namedStore: %+v in type: %v", namedStore, storeType) | ||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/* | ||
Copyright The Ratify Authors. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package notation | ||
|
||
import "testing" | ||
|
||
func TestNewCertStoreByTypeInvalidInput(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
conf verificationCertStores | ||
expectErr bool | ||
}{ | ||
{ | ||
name: "invalid certStores type", | ||
conf: verificationCertStores{ | ||
trustStoreTypeCA: []string{}, | ||
}, | ||
expectErr: true, | ||
}, | ||
{ | ||
name: "invalid certProviderList type", | ||
conf: verificationCertStores{ | ||
trustStoreTypeCA: verificationCertStores{ | ||
"certstore1": "akv1", | ||
"certstore2": []interface{}{"akv3", "akv4"}, | ||
}, | ||
}, | ||
expectErr: true, | ||
}, | ||
{ | ||
name: "invalid certProvider type", | ||
conf: verificationCertStores{ | ||
trustStoreTypeCA: verificationCertStores{ | ||
"certstore1": []interface{}{"akv1", []string{}}, | ||
}, | ||
}, | ||
expectErr: true, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
_, err := newCertStoreByType(tt.conf) | ||
if (err != nil) != tt.expectErr { | ||
t.Errorf("error = %v, expectErr = %v", err, tt.expectErr) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,12 +41,15 @@ import ( | |
"github.com/notaryproject/notation-go" | ||
notationVerifier "github.com/notaryproject/notation-go/verifier" | ||
"github.com/notaryproject/notation-go/verifier/trustpolicy" | ||
"github.com/notaryproject/notation-go/verifier/truststore" | ||
oci "github.com/opencontainers/image-spec/specs-go/v1" | ||
) | ||
|
||
const ( | ||
verifierType = "notation" | ||
defaultCertPath = "ratify-certs/notation/truststore" | ||
verifierType = "notation" | ||
defaultCertPath = "ratify-certs/notation/truststore" | ||
trustStoreTypeCA = string(truststore.TypeCA) | ||
trustStoreTypeypeSigningAuthority = string(truststore.TypeSigningAuthority) | ||
) | ||
|
||
// NotationPluginVerifierConfig describes the configuration of notation verifier | ||
|
@@ -56,8 +59,21 @@ type NotationPluginVerifierConfig struct { //nolint:revive // ignore linter to h | |
|
||
// VerificationCerts is array of directories containing certificates. | ||
VerificationCerts []string `json:"verificationCerts"` | ||
// VerificationCerts is map defining which keyvault certificates belong to which trust store | ||
VerificationCertStores map[string][]string `json:"verificationCertStores"` | ||
// VerificationCertStores defines a collection of Notary Project Trust Stores. | ||
// VerificationCertStores accepts new format map[string]map[string][]string | ||
// { | ||
// "ca": { | ||
// "certs": {"kv1", "kv2"}, | ||
// }, | ||
// "signingauthority": { | ||
// "certs": {"kv3"} | ||
// }, | ||
// } | ||
// VerificationCertStores accepts legacy format map[string][]string as well. | ||
// { | ||
// "certs": {"kv1", "kv2"}, | ||
// }, | ||
VerificationCertStores verificationCertStores `json:"verificationCertStores"` | ||
// TrustPolicyDoc represents a trustpolicy.json document. Reference: https://pkg.go.dev/github.com/notaryproject/[email protected]/verifier/trustpolicy#Document | ||
TrustPolicyDoc trustpolicy.Document `json:"trustPolicyDoc"` | ||
} | ||
|
@@ -168,11 +184,10 @@ func (v *notationPluginVerifier) Verify(ctx context.Context, | |
} | ||
|
||
func getVerifierService(conf *NotationPluginVerifierConfig, pluginDirectory string) (notation.Verifier, error) { | ||
store := &trustStore{ | ||
certPaths: conf.VerificationCerts, | ||
certStores: conf.VerificationCertStores, | ||
store, err := newTrustStore(conf.VerificationCerts, conf.VerificationCertStores) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return notationVerifier.New(&conf.TrustPolicyDoc, store, NewRatifyPluginManager(pluginDirectory)) | ||
} | ||
|
||
|
@@ -201,10 +216,37 @@ func parseVerifierConfig(verifierConfig config.VerifierConfig, _ string) (*Notat | |
|
||
defaultCertsDir := paths.Join(homedir.Get(), ratifyconfig.ConfigFileDir, defaultCertPath) | ||
conf.VerificationCerts = append(conf.VerificationCerts, defaultCertsDir) | ||
if len(conf.VerificationCertStores) > 0 { | ||
if err := normalizeVerificationCertsStores(conf); err != nil { | ||
return nil, err | ||
} | ||
} | ||
return conf, nil | ||
} | ||
|
||
// signatures should not have nested references | ||
func (v *notationPluginVerifier) GetNestedReferences() []string { | ||
return []string{} | ||
} | ||
|
||
// normalizeVerificationCertsStores normalize the structure does not match the latest spec | ||
func normalizeVerificationCertsStores(conf *NotationPluginVerifierConfig) error { | ||
isCertStoresByType, isLegacyCertStore := false, false | ||
for key := range conf.VerificationCertStores { | ||
if key != trustStoreTypeCA && key != trustStoreTypeypeSigningAuthority { | ||
isLegacyCertStore = true | ||
logger.GetLogger(context.Background(), logOpt).Debugf("Get VerificationCertStores in legacy format") | ||
} else { | ||
isCertStoresByType = true | ||
} | ||
} | ||
if isCertStoresByType && isLegacyCertStore { | ||
return re.ErrorCodeConfigInvalid.NewError(re.Verifier, conf.Name, re.EmptyLink, nil, "both old VerificationCertStores and new VerificationCertStores are provided, please provide only one", re.HideStackTrace) | ||
} else if !isCertStoresByType && isLegacyCertStore { | ||
// normalize <store>:<certs> to ca:<store><certs> if no store type is provided | ||
conf.VerificationCertStores = verificationCertStores{ | ||
trustStoreTypeCA: conf.VerificationCertStores, | ||
} | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.