Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
Signed-off-by: Patrick Zheng <[email protected]>
  • Loading branch information
Two-Hearts committed Nov 25, 2024
1 parent 7a31925 commit 3ef5c27
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 54 deletions.
66 changes: 66 additions & 0 deletions internal/algorithm/algorithm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright The Notary Project 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 algorithm

import (
"crypto/ecdsa"
"crypto/rsa"
"crypto/x509"
"errors"
"fmt"
)

// KeyType defines the key type.
type KeyType int

const (
KeyTypeRSA KeyType = 1 + iota // KeyType RSA
KeyTypeEC // KeyType EC
)

// KeySpec defines a key type and size.
type KeySpec struct {
// KeyType is the type of the key.
Type KeyType

// KeySize is the size of the key in bits.
Size int
}

// ExtractKeySpec extracts KeySpec from the signing certificate.
func ExtractKeySpec(signingCert *x509.Certificate) (KeySpec, error) {
switch key := signingCert.PublicKey.(type) {
case *rsa.PublicKey:
switch bitSize := key.Size() << 3; bitSize {
case 2048, 3072, 4096:
return KeySpec{
Type: KeyTypeRSA,
Size: bitSize,
}, nil
default:
return KeySpec{}, fmt.Errorf("rsa key size %d bits is not supported", bitSize)
}
case *ecdsa.PublicKey:
switch bitSize := key.Curve.Params().BitSize; bitSize {
case 256, 384, 521:
return KeySpec{
Type: KeyTypeEC,
Size: bitSize,
}, nil
default:
return KeySpec{}, fmt.Errorf("ecdsa key size %d bits is not supported", bitSize)
}
}
return KeySpec{}, errors.New("unsupported public key type")
}
116 changes: 116 additions & 0 deletions internal/algorithm/algorithm_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Copyright The Notary Project 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 algorithm

import (
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"reflect"
"strconv"
"testing"

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

func TestExtractKeySpec(t *testing.T) {
type testCase struct {
name string
cert *x509.Certificate
expect KeySpec
expectErr bool
}
// invalid cases
tests := []testCase{
{
name: "RSA wrong size",
cert: testhelper.GetUnsupportedRSACert().Cert,
expect: KeySpec{},
expectErr: true,
},
{
name: "ECDSA wrong size",
cert: testhelper.GetUnsupportedECCert().Cert,
expect: KeySpec{},
expectErr: true,
},
{
name: "Unsupported type",
cert: &x509.Certificate{
PublicKey: ed25519.PublicKey{},
},
expect: KeySpec{},
expectErr: true,
},
}

// append valid RSA cases
for _, k := range []int{2048, 3072, 4096} {
rsaRoot := testhelper.GetRSARootCertificate()
priv, _ := rsa.GenerateKey(rand.Reader, k)

certTuple := testhelper.GetRSACertTupleWithPK(
priv,
"Test RSA_"+strconv.Itoa(priv.Size()),
&rsaRoot,
)
tests = append(tests, testCase{
name: "RSA " + strconv.Itoa(k),
cert: certTuple.Cert,
expect: KeySpec{
Type: KeyTypeRSA,
Size: k,
},
expectErr: false,
})
}

// append valid EDCSA cases
for _, curve := range []elliptic.Curve{elliptic.P256(), elliptic.P384(), elliptic.P521()} {
ecdsaRoot := testhelper.GetECRootCertificate()
priv, _ := ecdsa.GenerateKey(curve, rand.Reader)
bitSize := priv.Params().BitSize

certTuple := testhelper.GetECDSACertTupleWithPK(
priv,
"Test EC_"+strconv.Itoa(bitSize),
&ecdsaRoot,
)
tests = append(tests, testCase{
name: "EC " + strconv.Itoa(bitSize),
cert: certTuple.Cert,
expect: KeySpec{
Type: KeyTypeEC,
Size: bitSize,
},
expectErr: false,
})
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
keySpec, err := ExtractKeySpec(tt.cert)

if (err != nil) != tt.expectErr {
t.Errorf("error = %v, expectErr = %v", err, tt.expectErr)
}
if !reflect.DeepEqual(keySpec, tt.expect) {
t.Errorf("expect %+v, got %+v", tt.expect, keySpec)
}
})
}
}
40 changes: 10 additions & 30 deletions signature/algorithm.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ package signature

import (
"crypto"
"crypto/ecdsa"
"crypto/rsa"
"crypto/x509"
"fmt"

"github.com/notaryproject/notation-core-go/internal/algorithm"
)

// Algorithm defines the signature algorithm.
Expand Down Expand Up @@ -68,35 +67,16 @@ func (alg Algorithm) Hash() crypto.Hash {

// ExtractKeySpec extracts KeySpec from the signing certificate.
func ExtractKeySpec(signingCert *x509.Certificate) (KeySpec, error) {
switch key := signingCert.PublicKey.(type) {
case *rsa.PublicKey:
switch bitSize := key.Size() << 3; bitSize {
case 2048, 3072, 4096:
return KeySpec{
Type: KeyTypeRSA,
Size: bitSize,
}, nil
default:
return KeySpec{}, &UnsupportedSigningKeyError{
Msg: fmt.Sprintf("rsa key size %d bits is not supported", bitSize),
}
}
case *ecdsa.PublicKey:
switch bitSize := key.Curve.Params().BitSize; bitSize {
case 256, 384, 521:
return KeySpec{
Type: KeyTypeEC,
Size: bitSize,
}, nil
default:
return KeySpec{}, &UnsupportedSigningKeyError{
Msg: fmt.Sprintf("ecdsa key size %d bits is not supported", bitSize),
}
ks, err := algorithm.ExtractKeySpec(signingCert)
if err != nil {
return KeySpec{}, &UnsupportedSigningKeyError{
Msg: err.Error(),
}
}
return KeySpec{}, &UnsupportedSigningKeyError{
Msg: "unsupported public key type",
}
return KeySpec{
Type: KeyType(ks.Type),
Size: ks.Size,
}, nil
}

// SignatureAlgorithm returns the signing algorithm associated with the KeySpec.
Expand Down
6 changes: 3 additions & 3 deletions signature/cose/envelope_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import (
const (
payloadString = "{\"targetArtifact\":{\"mediaType\":\"application/vnd.oci.image.manifest.v1+json\",\"digest\":\"sha256:73c803930ea3ba1e54bc25c2bdc53edd0284c62ed651fe7b00369da519a3c333\",\"size\":16724,\"annotations\":{\"io.wabbit-networks.buildId\":\"123\"}}}"

rfc3161TSAurl = "http://rfc3161timestamp.globalsign.com/advanced"
rfc3161TSAurl = "http://timestamp.digicert.com"
)

var (
Expand Down Expand Up @@ -129,7 +129,7 @@ func TestSign(t *testing.T) {
}
}

t.Run("with timestmap countersignature request", func(t *testing.T) {
t.Run("with timestamp countersignature request", func(t *testing.T) {
signRequest, err := newSignRequest("notary.x509", signature.KeyTypeRSA, 3072)
if err != nil {
t.Fatalf("newSignRequest() failed. Error = %s", err)
Expand All @@ -138,7 +138,7 @@ func TestSign(t *testing.T) {
if err != nil {
t.Fatal(err)
}
rootCerts, err := nx509.ReadCertificateFile("../../internal/timestamp/testdata/tsaRootCert.crt")
rootCerts, err := nx509.ReadCertificateFile("../../internal/timestamp/testdata/tsaRootCert.cer")
if err != nil || len(rootCerts) == 0 {
t.Fatal("failed to read root CA certificate:", err)
}
Expand Down
4 changes: 2 additions & 2 deletions signature/jws/envelope_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import (
"github.com/notaryproject/tspclient-go"
)

const rfc3161TSAurl = "http://rfc3161timestamp.globalsign.com/advanced"
const rfc3161TSAurl = "http://timestamp.digicert.com"

// remoteMockSigner is used to mock remote signer
type remoteMockSigner struct {
Expand Down Expand Up @@ -341,7 +341,7 @@ func TestSignWithTimestamp(t *testing.T) {
if err != nil {
t.Fatal(err)
}
rootCerts, err := nx509.ReadCertificateFile("../../internal/timestamp/testdata/tsaRootCert.crt")
rootCerts, err := nx509.ReadCertificateFile("../../internal/timestamp/testdata/tsaRootCert.cer")
if err != nil || len(rootCerts) == 0 {
t.Fatal("failed to read root CA certificate:", err)
}
Expand Down
26 changes: 7 additions & 19 deletions x509/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ package x509

import (
"bytes"
"crypto/ecdsa"
"crypto/rsa"
"crypto/x509"
"fmt"
"strings"
"time"

"github.com/notaryproject/notation-core-go/internal/algorithm"
)

func isSelfSigned(cert *x509.Certificate) (bool, error) {
Expand Down Expand Up @@ -95,23 +95,11 @@ func validateLeafKeyUsage(cert *x509.Certificate) error {
}

func validateSignatureAlgorithm(cert *x509.Certificate) error {
switch key := cert.PublicKey.(type) {
case *rsa.PublicKey:
switch bitSize := key.Size() << 3; bitSize {
case 2048, 3072, 4096:
return nil
default:
return fmt.Errorf("certificate with subject %q: rsa key size %d bits is not supported", cert.Subject, bitSize)
}
case *ecdsa.PublicKey:
switch bitSize := key.Curve.Params().BitSize; bitSize {
case 256, 384, 521:
return nil
default:
return fmt.Errorf("certificate with subject %q: ecdsa key size %d bits is not supported", cert.Subject, bitSize)
}
}
return fmt.Errorf("certificate with subject %q: unsupported public key type", cert.Subject)
_, err := algorithm.ExtractKeySpec(cert)
if err != nil {
return fmt.Errorf("certificate with subject %q: %w", cert.Subject, err)
}
return nil
}

func ekuToString(eku x509.ExtKeyUsage) string {
Expand Down

0 comments on commit 3ef5c27

Please sign in to comment.