Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: refactor pluginSigner to support new signature interface #131

Merged
merged 5 commits into from
Sep 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ go 1.18

require (
github.com/go-ldap/ldap/v3 v3.4.4
github.com/golang-jwt/jwt/v4 v4.4.2
github.com/notaryproject/notation-core-go v0.1.0-alpha.3
github.com/notaryproject/notation-core-go v0.1.0-alpha.3.0.20220921054535-009c09a9628e
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.0.2
github.com/oras-project/artifacts-spec v1.0.0-rc.2
Expand All @@ -15,6 +14,7 @@ require (
require (
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
github.com/opencontainers/distribution-spec/specs-go v0.0.0-20220620172159-4ab4752c3b86 // indirect
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ github.com/go-ldap/ldap/v3 v3.4.4 h1:qPjipEpt+qDa6SI/h1fzuGWoRUY+qqQ9sOZq67/PYUs
github.com/go-ldap/ldap/v3 v3.4.4/go.mod h1:fe1MsuN5eJJ1FeLT/LEBVdWfNWKh459R7aXgXtJC+aI=
github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/notaryproject/notation-core-go v0.1.0-alpha.3 h1:gzB+h5TGzuocWiJxuYZgE/FwUIbJyKAHfk2hWSBbCGg=
github.com/notaryproject/notation-core-go v0.1.0-alpha.3/go.mod h1:Wfyh5SrQ718JegKPhTs7y74rXg86tWd5NfOx2uHK1nI=
github.com/notaryproject/notation-core-go v0.1.0-alpha.3.0.20220921054535-009c09a9628e h1:n3wJRhIVbEGg497rtKV3IMaZJv2hFKYHCOtNIOAyLYw=
github.com/notaryproject/notation-core-go v0.1.0-alpha.3.0.20220921054535-009c09a9628e/go.mod h1:mM4M9wPdu0CGgh8f3wOcu0XMiXwEKWQurjBG4nmqQ4g=
github.com/opencontainers/distribution-spec/specs-go v0.0.0-20220620172159-4ab4752c3b86 h1:Oumw+lPnO8qNLTY2mrqPJZMoGExLi/0h/DdikoLTXVU=
github.com/opencontainers/distribution-spec/specs-go v0.0.0-20220620172159-4ab4752c3b86/go.mod h1:aA4vdXRS8E1TG7pLZOz85InHi3BiPdErh8IpJN6E0x4=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
Expand Down
8 changes: 3 additions & 5 deletions internal/mock/mocks.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package mock

import (
"context"
_ "embed"
nsigner "github.com/notaryproject/notation-core-go/signer"
)

import (
"context"
"github.com/notaryproject/notation-core-go/signature"
"github.com/notaryproject/notation-go"
"github.com/notaryproject/notation-go/plugin"
"github.com/notaryproject/notation-go/plugin/manager"
Expand Down Expand Up @@ -54,7 +52,7 @@ var (
Size: 100,
Annotations: Annotations,
}
PluginExtendedCriticalAttribute = nsigner.Attribute{
PluginExtendedCriticalAttribute = signature.Attribute{
Key: "SomeKey",
Critical: true,
Value: "SomeValue",
Expand Down
14 changes: 11 additions & 3 deletions notation.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ import (
"github.com/opencontainers/go-digest"
)

// Media type for Notary payload for OCI artifacts, which contains an artifact descriptor.
const MediaTypePayload = "application/vnd.cncf.notary.payload.v1+json"
// MediaTypePayloadV1 is the supported content type for signature's payload.
const MediaTypePayloadV1 = "application/vnd.cncf.notary.payload.v1+json"

// SigningAgent is the unprotected header field used by signature.
var SigningAgent = "Notation/1.0.0"

// Descriptor describes the artifact that needs to be signed.
type Descriptor struct {
Expand Down Expand Up @@ -65,7 +68,12 @@ type Signer interface {
}

// VerifyOptions contains parameters for Verifier.Verify.
type VerifyOptions struct{}
type VerifyOptions struct {
// SignatureMediaType is the envelope type of the signature.
// Currently only `application/jose+json`` is supported.
// TODO: in the future, application/cose will also be supported.
SignatureMediaType string
}

// Validate does basic validation on VerifyOptions.
func (opts VerifyOptions) Validate() error {
Expand Down
156 changes: 156 additions & 0 deletions plugin/algorithm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package plugin

import (
"errors"

"github.com/notaryproject/notation-core-go/signature"
)

// one of the following supported key spec names.
//
// https://github.com/notaryproject/notaryproject/blob/main/signature-specification.md#algorithm-selection
const (
RSA_2048 = "RSA-2048"
RSA_3072 = "RSA-3072"
RSA_4096 = "RSA-4096"
EC_256 = "EC-256"
EC_384 = "EC-384"
EC_521 = "EC-521"
)

// one of the following supported hash algorithm names.
//
// https://github.com/notaryproject/notaryproject/blob/main/signature-specification.md#algorithm-selection
const (
SHA_256 = "SHA-256"
SHA_384 = "SHA-384"
SHA_512 = "SHA-512"
)

// one of the following supported signing algorithm names.
//
// https://github.com/notaryproject/notaryproject/blob/main/signature-specification.md#algorithm-selection
const (
ECDSA_SHA_256 = "ECDSA-SHA-256"
ECDSA_SHA_384 = "ECDSA-SHA-384"
ECDSA_SHA_512 = "ECDSA-SHA-512"
RSASSA_PSS_SHA_256 = "RSASSA-PSS-SHA-256"
RSASSA_PSS_SHA_384 = "RSASSA-PSS-SHA-384"
RSASSA_PSS_SHA_512 = "RSASSA-PSS-SHA-512"
)

// KeySpecName returns the name of a keySpec according to the spec.
func KeySpecString(k signature.KeySpec) string {
switch k.Type {
case signature.KeyTypeEC:
switch k.Size {
case 256:
return EC_256
case 384:
return EC_384
case 521:
return EC_521
}
case signature.KeyTypeRSA:
switch k.Size {
case 2048:
return RSA_2048
case 3072:
return RSA_3072
case 4096:
return RSA_4096
}
}
return ""
}

// KeySpecHashName returns the name of hash function according to the spec.
func KeySpecHashString(k signature.KeySpec) string {
switch k.Type {
case signature.KeyTypeEC:
switch k.Size {
case 256:
return SHA_256
case 384:
return SHA_384
case 521:
return SHA_512
}
case signature.KeyTypeRSA:
switch k.Size {
case 2048:
return SHA_256
case 3072:
return SHA_384
case 4096:
return SHA_512
}
}
return ""
}

// ParseKeySpecFromName parses keySpec name to a signature.keySpec type.
func ParseKeySpec(raw string) (keySpec signature.KeySpec, err error) {
switch raw {
case RSA_2048:
keySpec.Size = 2048
keySpec.Type = signature.KeyTypeRSA
case RSA_3072:
keySpec.Size = 3072
keySpec.Type = signature.KeyTypeRSA
case RSA_4096:
keySpec.Size = 4096
keySpec.Type = signature.KeyTypeRSA
case EC_256:
keySpec.Size = 256
keySpec.Type = signature.KeyTypeEC
case EC_384:
keySpec.Size = 384
keySpec.Type = signature.KeyTypeEC
case EC_521:
keySpec.Size = 521
keySpec.Type = signature.KeyTypeEC
default:
keySpec = signature.KeySpec{}
err = errors.New("unknown key spec")
}
return
}

// SigningAlgorithmName returns the signing algorithm name of an algorithm according to the spec.
func SigningAlgorithmString(alg signature.Algorithm) string {
switch alg {
case signature.AlgorithmES256:
return ECDSA_SHA_256
case signature.AlgorithmES384:
return ECDSA_SHA_384
case signature.AlgorithmES512:
return ECDSA_SHA_512
case signature.AlgorithmPS256:
return RSASSA_PSS_SHA_256
case signature.AlgorithmPS384:
return RSASSA_PSS_SHA_384
case signature.AlgorithmPS512:
return RSASSA_PSS_SHA_512
}
return ""
}

// ParseSigningAlgorithFromName parses the signing algorithm name from a given string.
func ParseSigningAlgorithm(raw string) (signature.Algorithm, error) {
switch raw {
case ECDSA_SHA_256:
return signature.AlgorithmES256, nil
case ECDSA_SHA_384:
return signature.AlgorithmES384, nil
case ECDSA_SHA_512:
return signature.AlgorithmES512, nil
case RSASSA_PSS_SHA_256:
return signature.AlgorithmPS256, nil
case RSASSA_PSS_SHA_384:
return signature.AlgorithmPS384, nil
case RSASSA_PSS_SHA_512:
return signature.AlgorithmPS512, nil
}
return 0, errors.New("unknown signing algorithm")
}
Comment on lines +140 to +156
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we reuse mapping in SigningAlgorithmString function ?

22 changes: 10 additions & 12 deletions plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package plugin
import (
"context"
"time"

"github.com/notaryproject/notation-core-go/signer"
)

// Prefix is the prefix required on all plugin binary names.
Expand Down Expand Up @@ -127,17 +125,17 @@ type DescribeKeyResponse struct {

// One of following supported key types:
// https://github.com/notaryproject/notaryproject/blob/main/signature-specification.md#algorithm-selection
KeySpec signer.KeySpec `json:"keySpec"`
KeySpec string `json:"keySpec"`
}

// GenerateSignatureRequest contains the parameters passed in a generate-signature request.
type GenerateSignatureRequest struct {
ContractVersion string `json:"contractVersion"`
KeyID string `json:"keyId"`
KeySpec signer.KeySpec `json:"keySpec"`
Hash signer.HashAlgorithm `json:"hashAlgorithm"`
Payload []byte `json:"payload"`
PluginConfig map[string]string `json:"pluginConfig,omitempty"`
ContractVersion string `json:"contractVersion"`
KeyID string `json:"keyId"`
KeySpec string `json:"keySpec"`
Hash string `json:"hashAlgorithm"`
Payload []byte `json:"payload"`
PluginConfig map[string]string `json:"pluginConfig,omitempty"`
}

func (GenerateSignatureRequest) Command() Command {
Expand All @@ -146,9 +144,9 @@ func (GenerateSignatureRequest) Command() Command {

// GenerateSignatureResponse is the response of a generate-signature request.
type GenerateSignatureResponse struct {
KeyID string `json:"keyId"`
Signature []byte `json:"signature"`
SigningAlgorithm signer.SignatureAlgorithm `json:"signingAlgorithm"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use algorithm type instead of string?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/notaryproject/notaryproject/blob/main/specs/plugin-extensibility.md
I think spec requires a string value as the protocol to communicate with notation plugin.
E.g.

RSASSA-PSS-SHA-256: RSASSA-PSS with SHA-256
RSASSA-PSS-SHA-384: RSASSA-PSS with SHA-384

@shizhMSFT Can we reuse algorithm defined in notation-core-go?

KeyID string `json:"keyId"`
Signature []byte `json:"signature"`
SigningAlgorithm string `json:"signingAlgorithm"`

// Ordered list of certificates starting with leaf certificate
// and ending with root certificate.
Expand Down
17 changes: 17 additions & 0 deletions signature/envelope.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package signature

import (
"errors"

"github.com/notaryproject/notation-core-go/signature"
)

// ValidateEnvelopeMediaType validetes envelope media type is supported by notation-core-go.
func ValidateEnvelopeMediaType(mediaType string) error {
for _, types := range signature.RegisteredEnvelopeTypes() {
if mediaType == types {
return nil
}
}
return errors.New("invalid envelope media type")
}
46 changes: 46 additions & 0 deletions signature/envelope_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package signature

import (
"errors"
"testing"

"github.com/notaryproject/notation-core-go/signature/jws"
)

const invalidMediaType = "invalid"

func checkErrorEqual(expected, got error) bool {
if expected == nil && got == nil {
return true
}
if expected != nil && got != nil {
return expected.Error() == got.Error()
}
return false
}

func TestValidateEnvelopeMediaType(t *testing.T) {
tests := []struct {
name string
mediaType string
expectedErr error
}{
{
name: "jws signature media type",
mediaType: jws.MediaTypeEnvelope,
expectedErr: nil,
},
{
name: "invalid media type",
mediaType: invalidMediaType,
expectedErr: errors.New("invalid envelope media type"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := ValidateEnvelopeMediaType(tt.mediaType); !checkErrorEqual(tt.expectedErr, err) {
t.Fatalf("expected validate envelope media type err: %v, got: %v", tt.expectedErr, err)
}
})
}
}
Loading