Skip to content

Commit 062eea1

Browse files
author
zaihaoyin
committed
refactor:add verification plugin checker
Signed-off-by: zaihaoyin <[email protected]>
1 parent e44afe9 commit 062eea1

File tree

5 files changed

+68
-22
lines changed

5 files changed

+68
-22
lines changed

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ go 1.17
44

55
require (
66
github.com/go-ldap/ldap/v3 v3.4.4
7-
github.com/notaryproject/notation-core-go v0.0.0-20220901064119-7bf2b3e37c06
7+
github.com/notaryproject/notation-core-go v0.0.0-20220907034926-8cdaf86b4d7c
88
github.com/opencontainers/go-digest v1.0.0
99
github.com/opencontainers/image-spec v1.0.2
1010
github.com/oras-project/artifacts-spec v1.0.0-rc.2

go.sum

+2-3
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,10 @@ github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF
88
github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
99
github.com/go-ldap/ldap/v3 v3.4.4 h1:qPjipEpt+qDa6SI/h1fzuGWoRUY+qqQ9sOZq67/PYUs=
1010
github.com/go-ldap/ldap/v3 v3.4.4/go.mod h1:fe1MsuN5eJJ1FeLT/LEBVdWfNWKh459R7aXgXtJC+aI=
11-
github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
1211
github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
1312
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
14-
github.com/notaryproject/notation-core-go v0.0.0-20220901064119-7bf2b3e37c06 h1:tvnxwHtQEACckbLYYoyCPkAawNJk1BAsGFLrDhou2U0=
15-
github.com/notaryproject/notation-core-go v0.0.0-20220901064119-7bf2b3e37c06/go.mod h1:vRFI64uedpKUChiadJ/2q8jJNdKtxHa7Er1JbSnm8AY=
13+
github.com/notaryproject/notation-core-go v0.0.0-20220907034926-8cdaf86b4d7c h1:myIrd0sic/mu8PRt9/jvtkMmC/eVPsB2ufBGhbAM1hg=
14+
github.com/notaryproject/notation-core-go v0.0.0-20220907034926-8cdaf86b4d7c/go.mod h1:cebNvAIpFQXqBGGJa8c13FS1ln47c5qd8E6WjeQDkAA=
1615
github.com/opencontainers/distribution-spec/specs-go v0.0.0-20220620172159-4ab4752c3b86 h1:Oumw+lPnO8qNLTY2mrqPJZMoGExLi/0h/DdikoLTXVU=
1716
github.com/opencontainers/distribution-spec/specs-go v0.0.0-20220620172159-4ab4752c3b86/go.mod h1:aA4vdXRS8E1TG7pLZOz85InHi3BiPdErh8IpJN6E0x4=
1817
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=

verification/verifier.go

+13-4
Original file line numberDiff line numberDiff line change
@@ -151,13 +151,20 @@ func (v *Verifier) processSignature(ctx context.Context, sigBlob []byte, sigMani
151151

152152
// check if we need to verify using a plugin
153153
var pluginCapabilities []plugin.Capability
154-
verificationPluginName := GetVerificationPlugin(outcome.SignerInfo)
155-
if verificationPluginName != "" {
154+
verificationPluginName, err := getVerificationPlugin(outcome.SignerInfo)
155+
// use plugin, but getPluginName returns an error
156+
if err != nil && err != errExtendedAttributeNotExist {
157+
return err
158+
}
159+
if err == nil {
156160
installedPlugin, err := v.PluginManager.Get(ctx, verificationPluginName)
157161
if err != nil {
158162
return ErrorVerificationInconclusive{msg: fmt.Sprintf("error while locating the verification plugin %q, make sure the plugin is installed successfully before verifying the signature. error: %s", verificationPluginName, err)}
159163
}
160164

165+
if _, err := getVerificationPluginMinVersion(signerInfo); err != nil && err != errExtendedAttributeNotExist {
166+
return ErrorVerificationInconclusive{msg: fmt.Sprintf("error while getting plugin minimum version, error: %s", err)}
167+
}
161168
// TODO verify the plugin's version is equal to or greater than `outcome.SignerInfo.SignedAttributes.VerificationPluginMinVersion`
162169
// https://github.com/notaryproject/notation-go/issues/102
163170

@@ -234,8 +241,10 @@ func (v *Verifier) processSignature(ctx context.Context, sigBlob []byte, sigMani
234241
}
235242

236243
func (v *Verifier) processPluginResponse(capabilitiesToVerify []plugin.VerificationCapability, response *plugin.VerifySignatureResponse, outcome *SignatureVerificationOutcome) error {
237-
verificationPluginName := GetVerificationPlugin(outcome.SignerInfo)
238-
244+
verificationPluginName, err := getVerificationPlugin(outcome.SignerInfo)
245+
if err != nil {
246+
return err
247+
}
239248
// verify all extended critical attributes are processed by the plugin
240249
for _, attr := range outcome.SignerInfo.SignedAttributes.ExtendedAttributes {
241250
if attr.Critical {

verification/verifier_helpers.go

+51-13
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ package verification
33
import (
44
"context"
55
"crypto/x509"
6+
"errors"
67
"fmt"
8+
"regexp"
79
"strings"
810
"time"
911

@@ -13,6 +15,10 @@ import (
1315
"github.com/notaryproject/notation-go/registry"
1416
)
1517

18+
var errExtendedAttributeNotExist = errors.New("Extended attribute not exist")
19+
20+
var semVerRegEx = regexp.MustCompile("^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$")
21+
1622
// isCriticalFailure checks whether a VerificationResult fails the entire signature verification workflow.
1723
// signature verification workflow is considered failed if there is a VerificationResult with "Enforced" as the action but the result was unsuccessful
1824
func isCriticalFailure(result *VerificationResult) bool {
@@ -235,7 +241,10 @@ func verifyX509TrustedIdentities(certs []*x509.Certificate, trustPolicy *TrustPo
235241
}
236242

237243
func (v *Verifier) executePlugin(ctx context.Context, trustPolicy *TrustPolicy, capabilitiesToVerify []plugin.VerificationCapability, signerInfo *signature.SignerInfo, payloadInfo *signature.Payload) (*plugin.VerifySignatureResponse, error) {
238-
verificationPluginName := GetVerificationPlugin(signerInfo)
244+
verificationPluginName, err := getVerificationPlugin(signerInfo)
245+
if err != nil {
246+
return nil, err
247+
}
239248
var attributesToProcess []string
240249
extendedAttributes := make(map[string]interface{})
241250

@@ -298,20 +307,49 @@ func (v *Verifier) executePlugin(ctx context.Context, trustPolicy *TrustPolicy,
298307
return response, nil
299308
}
300309

301-
func GetVerificationPlugin(signerInfo *signature.SignerInfo) string {
302-
if verificationPlugin, err := signerInfo.ExtendedAttribute(VerificationPlugin); err == nil {
303-
if name, ok := verificationPlugin.Value.(string); ok {
304-
return name
305-
}
310+
// extractCriticalStringExtendedAttribute extracts a critical string Extended attribute from a signer
311+
func extractCriticalStringExtendedAttribute(signerInfo *signature.SignerInfo, key string) (string, error) {
312+
attr, err := signerInfo.ExtendedAttribute(key)
313+
// not exist
314+
if err != nil {
315+
return "", errExtendedAttributeNotExist
316+
}
317+
// not critical
318+
if !attr.Critical {
319+
return "", fmt.Errorf("%v is not a critical Extended attribute", key)
320+
}
321+
// not string
322+
val, ok := attr.Value.(string)
323+
if !ok {
324+
return "", fmt.Errorf("%v from Extended attribute is not a string", key)
306325
}
307-
return ""
326+
return val, nil
308327
}
309328

310-
func GetVerificationPluginMinVersion(signerInfo *signature.SignerInfo) string {
311-
if verificationPluginVersion, err := signerInfo.ExtendedAttribute(VerificationPluginMinVersion); err == nil {
312-
if version, ok := verificationPluginVersion.Value.(string); ok {
313-
return version
314-
}
329+
// getVerificationPlugin get plugin name from the Extended attributes
330+
func getVerificationPlugin(signerInfo *signature.SignerInfo) (string, error) {
331+
name, err := extractCriticalStringExtendedAttribute(signerInfo, VerificationPlugin)
332+
if err != nil {
333+
return "", err
334+
}
335+
// not an empty string
336+
if strings.TrimSpace(name) == "" {
337+
return "", fmt.Errorf("%v from Extended attribute is an empty string", VerificationPlugin)
338+
}
339+
return name, nil
340+
}
341+
342+
func getVerificationPluginMinVersion(signerInfo *signature.SignerInfo) (string, error) {
343+
version, err := extractCriticalStringExtendedAttribute(signerInfo, VerificationPluginMinVersion)
344+
if err != nil {
345+
return "", err
346+
}
347+
// empty version
348+
if strings.TrimSpace(version) == "" {
349+
return "", fmt.Errorf("%v from Extended attribute is an empty string", VerificationPluginMinVersion)
350+
}
351+
if !semVerRegEx.MatchString(version) {
352+
return "", fmt.Errorf("%v from Extended attribute is not a is not valid SemVer", VerificationPluginMinVersion)
315353
}
316-
return ""
354+
return version, nil
317355
}

verification/verifier_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ func assertNotationVerification(t *testing.T, scheme signature.SigningScheme) {
258258
policyDocument := dummyPolicyDocument()
259259
repo := mock.NewRepository()
260260
repo.GetResponse = invalidSigEnv
261-
expectedErr := fmt.Errorf("payload error: illegal base64 data at input byte 242")
261+
expectedErr := fmt.Errorf("signature is invalid. Error: illegal base64 data at input byte 242")
262262
testCases = append(testCases, testCase{
263263
verificationType: Integrity,
264264
verificationLevel: level,

0 commit comments

Comments
 (0)