Repository: sigstore/rekor-tiles
Pull request #154: Add entry hash algorithm config and validation
Author: login: cmurphy
Created: 2025-03-27T23:04:46Z | Merged: 2025-04-08T17:37:08Z

<!--
Thanks for opening a pull request! Please do not just delete this text.  The three fields below are mandatory.

Please remember to:
- This PR requires an issue. If it is a new feature, the issue should proceed the PR and will have allowed sufficient time for discussions to take place. Please use
issue tags such as "Closes #XYZ" or "Resolves sigstore/repo-name#XYZ".
  [documentation](https://docs.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword)
- ensure your commits are signed-off, as sigstore uses the [DCO](https://en.wikipedia.org/wiki/Developer_Certificate_of_Origin) using `git commit -s`, or `git commit -s --amend` if you want to amend already existing commits
- lastly, ensure there are no merge commits!

Thank you :)
-->

#### Summary
<!--
 Explain the **motivation** for making this change. What existing problem does the pull request solve? How can reviewers test this PR?
-->
Port over the configurable hash algorithms and key validation from
sigstore/rekor PR 1974. This both introduces a flag to restrict the
allowed signing algorithms for entries being submitted, as well as
validation to ensure the key used is within established constrictions
for the specified algorithm.

Much of this was borrowed from Rekor v1 with some modifications to
account for the different structure in rekor-tiles. Testing was done
here as unit tests rather than porting the script for the integration
tests from that PR.

Fixes https://github.com/sigstore/rekor-tiles/issues/100

#### Release Note
<!--
Add a release note for each of the following conditions:

* Config changes (additions, deletions, updates)
* API additions—new endpoint, new response fields, or newly accepted request parameters
* Database changes (any)
* Websocket additions or changes
* Anything noteworthy to an administrator running private sigstore instances (err on the side of over-communicating)
* New features and improvements, including behavioural changes, UI changes and CLI changes
* Bug fixes and fixes of previous known issues
* Deprecation warnings, breaking changes, or compatibility notes

If no release notes are required write NONE. Use past-tense.

-->

#### Documentation
<!--

Does this change require an update to documentation? How will users implement your new feature?

Please reference a PR within https://docs.sigstore.dev

-->



Diff:
diff --git a/cmd/rekor-server/app/serve.go b/cmd/rekor-server/app/serve.go
index 769bdb0c..d4b86e8f 100644
--- a/cmd/rekor-server/app/serve.go
+++ b/cmd/rekor-server/app/serve.go
@@ -21,15 +21,19 @@ import (
 	"fmt"
 	"log/slog"
 	"os"
+	"sort"
+	"strings"
 	"time"
 
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
 	"sigs.k8s.io/release-utils/version"
 
+	"github.com/sigstore/rekor-tiles/pkg/algorithmregistry"
 	"github.com/sigstore/rekor-tiles/pkg/server"
 	"github.com/sigstore/rekor-tiles/pkg/signerverifier"
 	"github.com/sigstore/rekor-tiles/pkg/tessera"
+	"github.com/sigstore/sigstore/pkg/signature"
 )
 
 var serveCmd = &cobra.Command{
@@ -96,7 +100,13 @@ var serveCmd = &cobra.Command{
 				os.Exit(1)
 			}
 		}
-		rekorServer := server.NewServer(tesseraStorage, readOnly)
+		algorithmRegistry, err := algorithmregistry.AlgorithmRegistry(viper.GetStringSlice("client-signing-algorithms"))
+		if err != nil {
+			slog.Error(fmt.Sprintf("failed to get algorithm registry: %v", err.Error()))
+			os.Exit(1)
+		}
+
+		rekorServer := server.NewServer(tesseraStorage, readOnly, algorithmRegistry)
 
 		server.Serve(
 			ctx,
@@ -162,6 +172,15 @@ func init() {
 	serveCmd.Flags().Uint("antispam-max-batch-size", tessera.DefaultAntispamMaxBatchSize, "maximum batch size for deduplication operations; recommend around 1500 for Spanner instances with 300 or more PU, or around 64 for smaller (e.g. 100 PU) instances")
 	serveCmd.Flags().Uint("antispam-pushback-threshold", tessera.DefaultAntispamPushbackThreshold, "maximum number of 'in-flight' add requests the antispam operator will allow before pushing back")
 
+	// allowed entry signing algorithms
+	keyAlgorithmTypes, err := defaultKeyAlgorithms()
+	if err != nil {
+		slog.Error(err.Error())
+		os.Exit(1)
+	}
+	keyAlgorithmHelp := fmt.Sprintf("signing algorithm to use for signing/hashing (allowed %s)", strings.Join(keyAlgorithmTypes, ", "))
+	serveCmd.Flags().StringSlice("client-signing-algorithms", keyAlgorithmTypes, keyAlgorithmHelp)
+
 	if err := viper.BindPFlags(serveCmd.Flags()); err != nil {
 		slog.Error(err.Error())
 		os.Exit(1)
@@ -174,3 +193,17 @@ var hashAlgMap = map[string]crypto.Hash{
 	"sha384": crypto.SHA384,
 	"sha512": crypto.SHA512,
 }
+
+func defaultKeyAlgorithms() ([]string, error) {
+	allowedClientSigningAlgorithms := algorithmregistry.AllowedClientSigningAlgorithms
+	keyAlgorithmTypes := []string{}
+	for _, keyAlgorithm := range allowedClientSigningAlgorithms {
+		keyFlag, err := signature.FormatSignatureAlgorithmFlag(keyAlgorithm)
+		if err != nil {
+			return nil, err
+		}
+		keyAlgorithmTypes = append(keyAlgorithmTypes, keyFlag)
+	}
+	sort.Strings(keyAlgorithmTypes)
+	return keyAlgorithmTypes, nil
+}
diff --git a/pkg/algorithmregistry/algorithmregistry.go b/pkg/algorithmregistry/algorithmregistry.go
new file mode 100644
index 00000000..a3c9bd0e
--- /dev/null
+++ b/pkg/algorithmregistry/algorithmregistry.go
@@ -0,0 +1,82 @@
+// Copyright 2025 The Sigstore 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 algorithmregistry
+
+import (
+	"crypto"
+	"fmt"
+
+	v1 "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1"
+	"github.com/sigstore/rekor-tiles/pkg/pki/x509"
+	"github.com/sigstore/sigstore/pkg/signature"
+)
+
+var (
+	AllowedClientSigningAlgorithms = []v1.PublicKeyDetails{
+		v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_2048_SHA256,
+		v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_3072_SHA256,
+		v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_4096_SHA256,
+		v1.PublicKeyDetails_PKIX_ECDSA_P256_SHA_256,
+		v1.PublicKeyDetails_PKIX_ECDSA_P384_SHA_384,
+		v1.PublicKeyDetails_PKIX_ECDSA_P521_SHA_512,
+		v1.PublicKeyDetails_PKIX_ED25519,
+		v1.PublicKeyDetails_PKIX_ED25519_PH,
+	}
+)
+
+// AlgorithmRegistry accepts a list of algorithms as strings, parses and formats them into a registry.
+func AlgorithmRegistry(algorithmOptions []string) (*signature.AlgorithmRegistryConfig, error) {
+	var algorithms []v1.PublicKeyDetails
+	if algorithmOptions == nil {
+		algorithms = AllowedClientSigningAlgorithms
+	} else {
+		for _, a := range algorithmOptions {
+			algorithm, err := signature.ParseSignatureAlgorithmFlag(a)
+			if err != nil {
+				return nil, fmt.Errorf("parsing signature algorithm flag: %w", err)
+			}
+			algorithms = append(algorithms, algorithm)
+		}
+	}
+	algorithmsStr := make([]string, len(algorithms))
+	var err error
+	for i, a := range algorithms {
+		algorithmsStr[i], err = signature.FormatSignatureAlgorithmFlag(a)
+		if err != nil {
+			return nil, fmt.Errorf("formatting signature algorithm flag: %w", err)
+		}
+	}
+	algorithmRegistry, err := signature.NewAlgorithmRegistryConfig(algorithms)
+	if err != nil {
+		return nil, fmt.Errorf("getting algorithm registry: %w", err)
+	}
+	return algorithmRegistry, nil
+}
+
+// CheckEntryAlgorithms checks that the combination public key and message
+// digest algorithm are allowed given an algorithm registry.
+func CheckEntryAlgorithms(keyObj *x509.PublicKey, alg crypto.Hash, algorithmRegistry *signature.AlgorithmRegistryConfig) (bool, error) {
+	publicKey := keyObj.CryptoPubKey()
+	// Check if all the verifiers public keys (together with the
+	// artifactHashValue) are allowed according to the policy
+	isPermitted, err := algorithmRegistry.IsAlgorithmPermitted(publicKey, alg)
+	if err != nil {
+		return false, fmt.Errorf("checking if algorithm is permitted: %w", err)
+	}
+	if !isPermitted {
+		return false, nil
+	}
+	return true, nil
+}
diff --git a/pkg/algorithmregistry/algorithmregistry_test.go b/pkg/algorithmregistry/algorithmregistry_test.go
new file mode 100644
index 00000000..28795057
--- /dev/null
+++ b/pkg/algorithmregistry/algorithmregistry_test.go
@@ -0,0 +1,63 @@
+// Copyright 2025 The Sigstore 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 algorithmregistry
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestAlgorithmRegistry(t *testing.T) {
+	tests := []struct {
+		name             string
+		algorithmOptions []string
+		wantErr          bool
+	}{
+		{
+			name:             "defaults",
+			algorithmOptions: nil,
+		},
+		{
+			name: "valid algorithms",
+			algorithmOptions: []string{
+				"ecdsa-sha2-384-nistp384",
+				"ecdsa-sha2-512-nistp521",
+				"ed25519",
+				"rsa-sign-pkcs1-3072-sha256",
+				"rsa-sign-pkcs1-4096-sha256",
+			},
+		},
+		{
+			name: "invalid algorithms",
+			algorithmOptions: []string{
+				"foo",
+				"bar",
+			},
+			wantErr: true,
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			got, gotErr := AlgorithmRegistry(test.algorithmOptions)
+			if test.wantErr {
+				assert.Error(t, gotErr)
+				return
+			}
+			assert.NoError(t, gotErr)
+			assert.NotNil(t, got)
+		})
+	}
+}
diff --git a/pkg/server/service.go b/pkg/server/service.go
index b58d68c4..5454c7d6 100644
--- a/pkg/server/service.go
+++ b/pkg/server/service.go
@@ -27,6 +27,7 @@ import (
 	"github.com/sigstore/rekor-tiles/pkg/tessera"
 	"github.com/sigstore/rekor-tiles/pkg/types/dsse"
 	"github.com/sigstore/rekor-tiles/pkg/types/hashedrekord"
+	"github.com/sigstore/sigstore/pkg/signature"
 	ttessera "github.com/transparency-dev/trillian-tessera"
 	"google.golang.org/genproto/googleapis/api/httpbody"
 	"google.golang.org/grpc"
@@ -47,18 +48,20 @@ type rekorServer interface {
 type Server struct {
 	pb.UnimplementedRekorServer
 	grpc_health_v1.UnimplementedHealthServer
-	storage  tessera.Storage
-	readOnly bool
+	storage           tessera.Storage
+	readOnly          bool
+	algorithmRegistry *signature.AlgorithmRegistryConfig
 }
 
-func NewServer(storage tessera.Storage, readOnly bool) *Server {
+func NewServer(storage tessera.Storage, readOnly bool, algorithmRegistry *signature.AlgorithmRegistryConfig) *Server {
 	if readOnly {
 		return &Server{
 			readOnly: readOnly,
 		}
 	}
 	return &Server{
-		storage: storage,
+		storage:           storage,
+		algorithmRegistry: algorithmRegistry,
 	}
 }
 
@@ -75,7 +78,7 @@ func (s *Server) CreateEntry(ctx context.Context, req *pb.CreateEntryRequest) (*
 	switch req.GetSpec().(type) {
 	case *pb.CreateEntryRequest_HashedRekordRequestV0_0_2:
 		hr := req.GetHashedRekordRequestV0_0_2()
-		entry, err := hashedrekord.ToLogEntry(hr)
+		entry, err := hashedrekord.ToLogEntry(hr, s.algorithmRegistry)
 		if err != nil {
 			slog.Warn("failed validating hashedrekord request", "error", err.Error())
 			return nil, status.Errorf(codes.InvalidArgument, "invalid hashedrekord request")
@@ -88,7 +91,7 @@ func (s *Server) CreateEntry(ctx context.Context, req *pb.CreateEntryRequest) (*
 		metricsCounter = getMetrics().newHashedRekordEntries
 	case *pb.CreateEntryRequest_DsseRequestV0_0_2:
 		ds := req.GetDsseRequestV0_0_2()
-		entry, err := dsse.ToLogEntry(ds)
+		entry, err := dsse.ToLogEntry(ds, s.algorithmRegistry)
 		if err != nil {
 			slog.Warn("failed validating dsse request", "error", err.Error())
 			return nil, status.Errorf(codes.InvalidArgument, "invalid dsse request")
diff --git a/pkg/server/service_test.go b/pkg/server/service_test.go
index caa44acd..5bfecdfc 100644
--- a/pkg/server/service_test.go
+++ b/pkg/server/service_test.go
@@ -25,6 +25,7 @@ import (
 
 	v1 "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1"
 	rekor_pb "github.com/sigstore/protobuf-specs/gen/pb-go/rekor/v1"
+	"github.com/sigstore/rekor-tiles/pkg/algorithmregistry"
 	pb "github.com/sigstore/rekor-tiles/pkg/generated/protobuf"
 	"github.com/stretchr/testify/assert"
 	ttessera "github.com/transparency-dev/trillian-tessera"
@@ -32,17 +33,23 @@ import (
 
 func TestNewServer(t *testing.T) {
 	storage := &mockStorage{}
-	server := NewServer(storage, false)
-	expectServer := &Server{storage: &mockStorage{}}
-	assert.Equal(t, expectServer, server)
+	algReg, err := algorithmregistry.AlgorithmRegistry([]string{"ecdsa-sha2-256-nistp256"})
+	if err != nil {
+		t.Fatal(err)
+	}
+	server := NewServer(storage, false, algReg)
+	assert.NoError(t, err)
+	assert.NotNil(t, server.storage)
+	assert.NotNil(t, server.algorithmRegistry)
 }
 
 func TestCreateEntry(t *testing.T) {
 	tests := []struct {
-		name        string
-		req         *pb.CreateEntryRequest
-		addFn       func() (*rekor_pb.TransparencyLogEntry, error)
-		expectError error
+		name                    string
+		req                     *pb.CreateEntryRequest
+		addFn                   func() (*rekor_pb.TransparencyLogEntry, error)
+		clientSigningAlgorithms []string
+		expectError             error
 	}{
 		{
 			name: "valid hashedrekord",
@@ -67,7 +74,8 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeLw7gX40qy1z7JUhGMAaaDITbV7p
 					},
 				},
 			},
-			addFn: func() (*rekor_pb.TransparencyLogEntry, error) { return &rekor_pb.TransparencyLogEntry{}, nil },
+			addFn:                   func() (*rekor_pb.TransparencyLogEntry, error) { return &rekor_pb.TransparencyLogEntry{}, nil },
+			clientSigningAlgorithms: []string{"ecdsa-sha2-256-nistp256"},
 		},
 		{
 			name: "valid dsse",
@@ -100,7 +108,8 @@ qSTHiQhkA4/0ZAsJtmzn/v4HdeZKTCQcsHq5IwM/LtbmEdv9ChO9M3cg9g==
 					},
 				},
 			},
-			addFn: func() (*rekor_pb.TransparencyLogEntry, error) { return &rekor_pb.TransparencyLogEntry{}, nil },
+			addFn:                   func() (*rekor_pb.TransparencyLogEntry, error) { return &rekor_pb.TransparencyLogEntry{}, nil },
+			clientSigningAlgorithms: []string{"ecdsa-sha2-256-nistp256"},
 		},
 		{
 			name: "invalid hashedrekord",
@@ -109,8 +118,9 @@ qSTHiQhkA4/0ZAsJtmzn/v4HdeZKTCQcsHq5IwM/LtbmEdv9ChO9M3cg9g==
 					HashedRekordRequestV0_0_2: &pb.HashedRekordRequestV0_0_2{},
 				},
 			},
-			addFn:       func() (*rekor_pb.TransparencyLogEntry, error) { return &rekor_pb.TransparencyLogEntry{}, nil },
-			expectError: fmt.Errorf("invalid hashedrekord request"),
+			addFn:                   func() (*rekor_pb.TransparencyLogEntry, error) { return &rekor_pb.TransparencyLogEntry{}, nil },
+			clientSigningAlgorithms: []string{"ecdsa-sha2-256-nistp256"},
+			expectError:             fmt.Errorf("invalid hashedrekord request"),
 		},
 		{
 			name: "invalid dsse",
@@ -119,8 +129,9 @@ qSTHiQhkA4/0ZAsJtmzn/v4HdeZKTCQcsHq5IwM/LtbmEdv9ChO9M3cg9g==
 					DsseRequestV0_0_2: &pb.DSSERequestV0_0_2{},
 				},
 			},
-			addFn:       func() (*rekor_pb.TransparencyLogEntry, error) { return &rekor_pb.TransparencyLogEntry{}, nil },
-			expectError: fmt.Errorf("invalid dsse request"),
+			addFn:                   func() (*rekor_pb.TransparencyLogEntry, error) { return &rekor_pb.TransparencyLogEntry{}, nil },
+			clientSigningAlgorithms: []string{"ecdsa-sha2-256-nistp256"},
+			expectError:             fmt.Errorf("invalid dsse request"),
 		},
 		{
 			name: "failed integration",
@@ -145,14 +156,45 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeLw7gX40qy1z7JUhGMAaaDITbV7p
 					},
 				},
 			},
-			addFn:       func() (*rekor_pb.TransparencyLogEntry, error) { return nil, fmt.Errorf("timed out") },
-			expectError: fmt.Errorf("failed to integrate entry"),
+			addFn:                   func() (*rekor_pb.TransparencyLogEntry, error) { return nil, fmt.Errorf("timed out") },
+			clientSigningAlgorithms: []string{"ecdsa-sha2-256-nistp256"},
+			expectError:             fmt.Errorf("failed to integrate entry"),
+		},
+		{
+			name: "hashedrekord signed with disallowed algorithm",
+			req: &pb.CreateEntryRequest{
+				Spec: &pb.CreateEntryRequest_HashedRekordRequestV0_0_2{
+					HashedRekordRequestV0_0_2: &pb.HashedRekordRequestV0_0_2{
+						Signature: &pb.Signature{
+							Content: b64DecodeOrDie(t, "MEYCIQC59oLS3MsCqm0xCxPOy+8FdQK4RYCZE036s3q1ECfcagIhAJ4ATXlCSdFrklKAS8No0PsAE9uLi37TCbIfRXASJTTb"),
+							Verifier: &pb.Verifier{
+								Verifier: &pb.Verifier_PublicKey{
+									PublicKey: &pb.PublicKey{
+										RawBytes: []byte(`-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeLw7gX40qy1z7JUhGMAaaDITbV7p
+2D+C5G9xPEsy/PVAo9H0mgS4NYzpGirkXxBht+IvvL19WR1X9ANXha5ldQ==
+-----END PUBLIC KEY-----`),
+									},
+								},
+							},
+						},
+						Digest: hexDecodeOrDie(t, "5b3513f580c8397212ff2c8f459c199efc0c90e4354a5f3533adf0a3fff3a530"),
+					},
+				},
+			},
+			addFn:                   func() (*rekor_pb.TransparencyLogEntry, error) { return &rekor_pb.TransparencyLogEntry{}, nil },
+			clientSigningAlgorithms: []string{"rsa-sign-pkcs1-4096-sha256"},
+			expectError:             fmt.Errorf("invalid hashedrekord request"),
 		},
 	}
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
 			storage := &mockStorage{addFn: test.addFn}
-			server := NewServer(storage, false)
+			algReg, err := algorithmregistry.AlgorithmRegistry(test.clientSigningAlgorithms)
+			if err != nil {
+				t.Fatal(err)
+			}
+			server := NewServer(storage, false, algReg)
 			gotTle, gotErr := server.CreateEntry(context.Background(), test.req)
 			if test.expectError == nil {
 				assert.NoError(t, gotErr)
diff --git a/pkg/types/dsse/dsse.go b/pkg/types/dsse/dsse.go
index ed2fd427..7632e55f 100644
--- a/pkg/types/dsse/dsse.go
+++ b/pkg/types/dsse/dsse.go
@@ -27,6 +27,7 @@ import (
 
 	"github.com/secure-systems-lab/go-securesystemslib/dsse"
 	pbdsse "github.com/sigstore/protobuf-specs/gen/pb-go/dsse"
+	"github.com/sigstore/rekor-tiles/pkg/algorithmregistry"
 	pb "github.com/sigstore/rekor-tiles/pkg/generated/protobuf"
 	"github.com/sigstore/rekor-tiles/pkg/pki/x509"
 	"github.com/sigstore/rekor-tiles/pkg/types/verifier"
@@ -36,7 +37,7 @@ import (
 
 // ToLogEntry validates a request and converts it to a log entry type for inclusion in the log
 // TODO(#178) separate out ToLogEntry into proto validation, cyrpto validation and log entry conversion
-func ToLogEntry(ds *pb.DSSERequestV0_0_2) (*pb.DSSELogEntryV0_0_2, error) {
+func ToLogEntry(ds *pb.DSSERequestV0_0_2, algorithmRegistry *signature.AlgorithmRegistryConfig) (*pb.DSSELogEntryV0_0_2, error) {
 	if ds.Envelope == nil {
 		return nil, fmt.Errorf("missing envelope")
 	}
@@ -61,7 +62,8 @@ func ToLogEntry(ds *pb.DSSERequestV0_0_2) (*pb.DSSELogEntryV0_0_2, error) {
 			allPubKeyBytes[v] = cert.RawBytes
 		}
 	}
-	signerVerifiers, err := verifyEnvelope(allPubKeyBytes, ds.Envelope)
+	// TODO: infer hash algorithm from public key info (#176)
+	signerVerifiers, err := verifyEnvelope(allPubKeyBytes, ds.Envelope, crypto.SHA256, algorithmRegistry)
 	if err != nil {
 		return nil, err
 	}
@@ -79,7 +81,7 @@ func ToLogEntry(ds *pb.DSSERequestV0_0_2) (*pb.DSSELogEntryV0_0_2, error) {
 // verifyEnvelope takes in an array of possible key bytes and attempts to parse them as x509 public keys.
 // it then uses these to verify the envelope and makes sure that every signature on the envelope is verified.
 // it returns a list of SignatureAndVerifier mapping each signature in the envelope to a provided verifier
-func verifyEnvelope(allPubKeyBytes map[*pb.Verifier][]byte, pbenv *pbdsse.Envelope) ([]*pb.Signature, error) {
+func verifyEnvelope(allPubKeyBytes map[*pb.Verifier][]byte, pbenv *pbdsse.Envelope, alg crypto.Hash, algorithmRegistry *signature.AlgorithmRegistryConfig) ([]*pb.Signature, error) {
 	env := FromProto(pbenv)
 	savs := make([]*pb.Signature, 0, len(allPubKeyBytes))
 	// generate a fake id for these keys so we can get back to the key bytes and match them to their corresponding signature
@@ -97,6 +99,14 @@ func verifyEnvelope(allPubKeyBytes map[*pb.Verifier][]byte, pbenv *pbdsse.Envelo
 			return nil, fmt.Errorf("could not parse public key as x509: %w", err)
 		}
 
+		valid, err := algorithmregistry.CheckEntryAlgorithms(key, alg, algorithmRegistry)
+		if err != nil {
+			return nil, fmt.Errorf("checking entry algorithm: %w", err)
+		}
+		if !valid {
+			return nil, fmt.Errorf("invalid entry algorithm %s", alg.String())
+		}
+
 		vfr, err := signature.LoadVerifier(key.CryptoPubKey(), crypto.SHA256)
 		if err != nil {
 			return nil, fmt.Errorf("could not load verifier: %w", err)
diff --git a/pkg/types/dsse/dsse_test.go b/pkg/types/dsse/dsse_test.go
index 3f06599d..38a97654 100644
--- a/pkg/types/dsse/dsse_test.go
+++ b/pkg/types/dsse/dsse_test.go
@@ -23,13 +23,12 @@ import (
 
 	"github.com/go-test/deep"
 	dsset "github.com/secure-systems-lab/go-securesystemslib/dsse"
-	"google.golang.org/protobuf/encoding/protojson"
-
-	"github.com/sigstore/protobuf-specs/gen/pb-go/dsse"
-
 	v1 "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1"
+	"github.com/sigstore/protobuf-specs/gen/pb-go/dsse"
 	pb "github.com/sigstore/rekor-tiles/pkg/generated/protobuf"
+	"github.com/sigstore/sigstore/pkg/signature"
 	"github.com/stretchr/testify/assert"
+	"google.golang.org/protobuf/encoding/protojson"
 )
 
 var (
@@ -59,10 +58,11 @@ func TestToLogEntry(t *testing.T) {
 	var keySignature = b64DecodeOrDie(t, "MEUCIQCSWas1Y9bI7aDNrBdHlzrFH8ch7B7IM+pJK86mtjkbJAIgaeCltz6vs20DP2sJ7IBihvcrdqGn3ivuV/KNPlMOetk=")
 	var certSignature = b64DecodeOrDie(t, "MEUCIQDoYuLoinEz/gM6B+hEn/0d47lmRDitQ3LfL9vH0sF/gQIgPqVgoBTRsMSPYMXYuJYYCIaTpnuppqQaTSTRn0ubwLI=")
 	tests := []struct {
-		name          string
-		dsse          *pb.DSSERequestV0_0_2
-		expectErr     error
-		expectedEntry *pb.DSSELogEntryV0_0_2
+		name              string
+		dsse              *pb.DSSERequestV0_0_2
+		allowedAlgorithms []v1.PublicKeyDetails
+		expectErr         error
+		expectedEntry     *pb.DSSELogEntryV0_0_2
 	}{
 		{
 			name: "valid dsse",
@@ -243,10 +243,44 @@ func TestToLogEntry(t *testing.T) {
 				},
 			},
 		},
+		{
+			name: "mismatched key algorithm",
+			dsse: &pb.DSSERequestV0_0_2{
+				Envelope: &dsse.Envelope{
+					Payload:     payload,
+					PayloadType: "application/vnd.in-toto+json",
+					Signatures: []*dsse.Signature{
+						{
+							Sig:   keySignature,
+							Keyid: "",
+						},
+					},
+				},
+				Verifiers: []*pb.Verifier{
+					{
+						Verifier: &pb.Verifier_PublicKey{
+							PublicKey: &pb.PublicKey{
+								RawBytes: []byte(publicKey),
+							},
+						},
+					},
+				},
+			},
+			allowedAlgorithms: []v1.PublicKeyDetails{v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_4096_SHA256, v1.PublicKeyDetails_PKIX_ED25519_PH},
+			expectErr:         fmt.Errorf("invalid entry algorithm"),
+		},
 	}
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
-			entry, gotErr := ToLogEntry(test.dsse)
+			allowedAlgs := test.allowedAlgorithms
+			if allowedAlgs == nil {
+				allowedAlgs = []v1.PublicKeyDetails{v1.PublicKeyDetails_PKIX_ECDSA_P256_SHA_256}
+			}
+			algReg, err := signature.NewAlgorithmRegistryConfig(allowedAlgs)
+			if err != nil {
+				t.Fatal(err)
+			}
+			entry, gotErr := ToLogEntry(test.dsse, algReg)
 			if test.expectErr == nil {
 				assert.NoError(t, gotErr)
 				if diff := deep.Equal(test.expectedEntry, entry); diff != nil {
diff --git a/pkg/types/hashedrekord/hashedrekord.go b/pkg/types/hashedrekord/hashedrekord.go
index 34571f16..4bf9d374 100644
--- a/pkg/types/hashedrekord/hashedrekord.go
+++ b/pkg/types/hashedrekord/hashedrekord.go
@@ -16,19 +16,20 @@ package hashedrekord
 
 import (
 	"bytes"
-	"crypto"
 	"fmt"
 
 	v1 "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1"
+	"github.com/sigstore/rekor-tiles/pkg/algorithmregistry"
 	pb "github.com/sigstore/rekor-tiles/pkg/generated/protobuf"
 	"github.com/sigstore/rekor-tiles/pkg/pki/x509"
 	"github.com/sigstore/rekor-tiles/pkg/types/verifier"
+	"github.com/sigstore/sigstore/pkg/signature"
 	"github.com/sigstore/sigstore/pkg/signature/options"
 )
 
 // ToLogEntry validates a request and converts it to a log entry type for inclusion in the log
 // TODO(#178) separate out ToLogEntry into proto validation, cyrpto validation and log entry conversion
-func ToLogEntry(hr *pb.HashedRekordRequestV0_0_2) (*pb.HashedRekordLogEntryV0_0_2, error) {
+func ToLogEntry(hr *pb.HashedRekordRequestV0_0_2, algorithmRegistry *signature.AlgorithmRegistryConfig) (*pb.HashedRekordLogEntryV0_0_2, error) {
 	if hr.Signature == nil || len(hr.Signature.Content) == 0 {
 		return nil, fmt.Errorf("missing signature")
 	}
@@ -57,10 +58,20 @@ func ToLogEntry(hr *pb.HashedRekordRequestV0_0_2) (*pb.HashedRekordLogEntryV0_0_
 		return nil, fmt.Errorf("parsing public key: %w", err)
 	}
 
-	// TODO: Look up hash with sigstore/sigstore's GetAlgorithmDetails(hr.Signature.Verifier.KeyDetails).GetHashType()
-	// Update hardcoded SHA256 during signature verification and as output
+	algDetails, err := signature.GetAlgorithmDetails(hr.Signature.Verifier.KeyDetails)
+	if err != nil {
+		return nil, fmt.Errorf("getting key algorithm details: %w", err)
+	}
+	alg := algDetails.GetHashType()
+	valid, err := algorithmregistry.CheckEntryAlgorithms(keyObj, alg, algorithmRegistry)
+	if err != nil {
+		return nil, fmt.Errorf("checking entry algorithm: %w", err)
+	}
+	if !valid {
+		return nil, fmt.Errorf("invalid entry algorithm %s", alg.String())
+	}
 
-	if err := sigObj.Verify(nil, keyObj, options.WithDigest(hr.Digest), options.WithCryptoSignerOpts(crypto.SHA256)); err != nil {
+	if err := sigObj.Verify(nil, keyObj, options.WithDigest(hr.Digest), options.WithCryptoSignerOpts(alg)); err != nil {
 		return nil, fmt.Errorf("verifying signature: %w", err)
 	}
 
diff --git a/pkg/types/hashedrekord/hashedrekord_test.go b/pkg/types/hashedrekord/hashedrekord_test.go
index 3613d787..ee35b2de 100644
--- a/pkg/types/hashedrekord/hashedrekord_test.go
+++ b/pkg/types/hashedrekord/hashedrekord_test.go
@@ -22,6 +22,7 @@ import (
 
 	v1 "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1"
 	pb "github.com/sigstore/rekor-tiles/pkg/generated/protobuf"
+	"github.com/sigstore/sigstore/pkg/signature"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -50,9 +51,10 @@ fRnK+CuN46tvzGu+9A==
 
 func TestToLogEntry(t *testing.T) {
 	tests := []struct {
-		name         string
-		hashedrekord *pb.HashedRekordRequestV0_0_2
-		expectErr    error
+		name              string
+		hashedrekord      *pb.HashedRekordRequestV0_0_2
+		allowedAlgorithms []v1.PublicKeyDetails
+		expectErr         error
 	}{
 		{
 			name: "valid hashedrekord",
@@ -150,10 +152,37 @@ func TestToLogEntry(t *testing.T) {
 				Digest: hexDecodeOrDie(t, hexEncodedDigest),
 			},
 		},
+		{
+			name: "mismatched key algorithm",
+			hashedrekord: &pb.HashedRekordRequestV0_0_2{
+				Signature: &pb.Signature{
+					Content: b64DecodeOrDie(t, b64EncodedSignature),
+					Verifier: &pb.Verifier{
+						Verifier: &pb.Verifier_PublicKey{
+							PublicKey: &pb.PublicKey{
+								RawBytes: []byte(publicKey),
+							},
+						},
+						KeyDetails: v1.PublicKeyDetails_PKIX_ECDSA_P256_SHA_256,
+					},
+				},
+				Digest: hexDecodeOrDie(t, hexEncodedDigest),
+			},
+			allowedAlgorithms: []v1.PublicKeyDetails{v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_4096_SHA256, v1.PublicKeyDetails_PKIX_ED25519_PH},
+			expectErr:         fmt.Errorf("invalid entry algorithm SHA-256"),
+		},
 	}
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
-			_, gotErr := ToLogEntry(test.hashedrekord)
+			allowedAlgs := test.allowedAlgorithms
+			if allowedAlgs == nil {
+				allowedAlgs = []v1.PublicKeyDetails{v1.PublicKeyDetails_PKIX_ECDSA_P256_SHA_256}
+			}
+			algReg, err := signature.NewAlgorithmRegistryConfig(allowedAlgs)
+			if err != nil {
+				t.Fatal(err)
+			}
+			_, gotErr := ToLogEntry(test.hashedrekord, algReg)
 			if test.expectErr == nil {
 				assert.NoError(t, gotErr)
 			} else {


Reviews:
user: login: Hayden-IO
body: Can we add this for DSSE too? The reason we only added it for hashedrekord in Rekor v1 was to avoid having to update every type while testing out this feature.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-30T19:12:38Z
user: login: Hayden-IO
body: Can we file an issue to follow up on DSSE?
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T21:04:02Z
user: login: cmurphy
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T22:51:15Z
user: login: cmurphy
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T20:51:26Z
user: login: loosebazooka
body: looks good to me, just some minor questions and comments
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-04T19:49:19Z
user: login: cmurphy
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T20:05:06Z
user: login: loosebazooka
state: DISMISSED
author_association: MEMBER
submitted_at: 2025-04-07T15:34:08Z
user: login: cmurphy
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:00:06Z
user: login: Hayden-IO
body: LGTM, just two small things
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T22:30:44Z
user: login: cmurphy
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T16:43:40Z
user: login: Hayden-IO
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T16:45:28Z
user: login: loosebazooka
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-08T17:32:30Z

Review comments:
diff_hunk: @@ -0,0 +1,65 @@
+// Copyright 2025 The Sigstore 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 server
+
+import (
+	"fmt"
+
+	v1 "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1"
+	"github.com/sigstore/sigstore/pkg/signature"
+)
+
+var (
+	AllowedClientSigningAlgorithms = []v1.PublicKeyDetails{
+		v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_2048_SHA256,
+		v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_3072_SHA256,
+		v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_4096_SHA256,
+		v1.PublicKeyDetails_PKIX_ECDSA_P256_SHA_256,
+		v1.PublicKeyDetails_PKIX_ECDSA_P384_SHA_384,
+		v1.PublicKeyDetails_PKIX_ECDSA_P521_SHA_512,
+		v1.PublicKeyDetails_PKIX_ED25519,
+		v1.PublicKeyDetails_PKIX_ED25519_PH,
+	}
+
+	DefaultClientSigningAlgorithms = AllowedClientSigningAlgorithms
path: pkg/server/algorithmregistry.go
user: login: Hayden-IO
body: Can we use `AllowedClientSigningAlgorithms` or do we need another global var?
created_at: 2025-04-02T21:01:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,65 @@
+// Copyright 2025 The Sigstore 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 server
+
+import (
+	"fmt"
+
+	v1 "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1"
+	"github.com/sigstore/sigstore/pkg/signature"
+)
+
+var (
+	AllowedClientSigningAlgorithms = []v1.PublicKeyDetails{
+		v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_2048_SHA256,
+		v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_3072_SHA256,
+		v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_4096_SHA256,
+		v1.PublicKeyDetails_PKIX_ECDSA_P256_SHA_256,
+		v1.PublicKeyDetails_PKIX_ECDSA_P384_SHA_384,
+		v1.PublicKeyDetails_PKIX_ECDSA_P521_SHA_512,
+		v1.PublicKeyDetails_PKIX_ED25519,
+		v1.PublicKeyDetails_PKIX_ED25519_PH,
+	}
+
+	DefaultClientSigningAlgorithms = AllowedClientSigningAlgorithms
path: pkg/server/algorithmregistry.go
user: login: cmurphy
body: We don't need it, I'm guessing the original author wanted to make a semantic distinction between the algorithms rekor allows and the defaults if none are specified.
created_at: 2025-04-02T22:51:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -61,7 +62,7 @@ func ToLogEntry(ds *pb.DSSERequestV0_0_2) (*pb.DSSELogEntryV0_0_2, error) {
 			allPubKeyBytes[v] = cert.RawBytes
 		}
 	}
-	signerVerifiers, err := verifyEnvelope(allPubKeyBytes, ds.Envelope)
+	signerVerifiers, err := verifyEnvelope(allPubKeyBytes, ds.Envelope, crypto.SHA256, algorithmRegistry)
path: pkg/types/dsse/dsse.go
user: login: cmurphy
body: Should merge https://github.com/sigstore/rekor-tiles/pull/179 first to avoid hardcoding the algorithm
created_at: 2025-04-03T20:51:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -61,7 +62,7 @@ func ToLogEntry(ds *pb.DSSERequestV0_0_2) (*pb.DSSELogEntryV0_0_2, error) {
 			allPubKeyBytes[v] = cert.RawBytes
 		}
 	}
-	signerVerifiers, err := verifyEnvelope(allPubKeyBytes, ds.Envelope)
+	signerVerifiers, err := verifyEnvelope(allPubKeyBytes, ds.Envelope, crypto.SHA256, algorithmRegistry)
path: pkg/types/dsse/dsse.go
user: login: loosebazooka
body: we're reworking PR: #179 as described in issue: #176 , so lets hardcode for now.
created_at: 2025-04-04T19:22:03Z
author_association: MEMBER
diff_hunk: @@ -97,6 +98,14 @@ func verifyEnvelope(allPubKeyBytes map[*pb.Verifier][]byte, pbenv *pbdsse.Envelo
 			return nil, fmt.Errorf("could not parse public key as x509: %w", err)
 		}
 
+		valid, err := types.CheckEntryAlgorithms(key, alg, algorithmRegistry)
+		if err != nil {
+			return nil, fmt.Errorf("checking entry algorithm: %w", err)
+		}
+		if !valid {
+			return nil, fmt.Errorf("invalid entry algorithm")
path: pkg/types/dsse/dsse.go
user: login: loosebazooka
body: include the key,alg in error?
created_at: 2025-04-04T19:37:09Z
author_association: MEMBER
diff_hunk: @@ -68,6 +70,13 @@ func ToLogEntry(hr *pb.HashedRekordRequestV0_0_2) (*pb.HashedRekordLogEntryV0_0_
 	default:
 		alg = crypto.SHA256
 	}
+	valid, err := types.CheckEntryAlgorithms(keyObj, alg, algorithmRegistry)
+	if err != nil {
+		return nil, fmt.Errorf("checking entry algorithm: %w", err)
+	}
+	if !valid {
+		return nil, fmt.Errorf("invalid entry algorithm")
path: pkg/types/hashedrekord/hashedrekord.go
user: login: loosebazooka
body: include the bad key/algorithm here too?
created_at: 2025-04-04T19:47:25Z
author_association: MEMBER
diff_hunk: @@ -47,19 +49,25 @@ type rekorServer interface {
 type Server struct {
 	pb.UnimplementedRekorServer
 	grpc_health_v1.UnimplementedHealthServer
-	storage  tessera.Storage
-	readOnly bool
+	storage           tessera.Storage
+	readOnly          bool
+	algorithmRegistry *signature.AlgorithmRegistryConfig
 }
 
-func NewServer(storage tessera.Storage, readOnly bool) *Server {
+func NewServer(storage tessera.Storage, readOnly bool, allowedKeyAlgorithms []string) (*Server, error) {
 	if readOnly {
 		return &Server{
 			readOnly: readOnly,
-		}
+		}, nil
 	}
-	return &Server{
-		storage: storage,
+	algorithmRegistry, err := algorithmRegistry(allowedKeyAlgorithms)
path: pkg/server/service.go
user: login: loosebazooka
body: could we preparse this and avoid NewServer erroring? I don't know that that even matters, especially if changing this makes everything look worse.
created_at: 2025-04-04T19:48:50Z
author_association: MEMBER
diff_hunk: @@ -47,19 +49,25 @@ type rekorServer interface {
 type Server struct {
 	pb.UnimplementedRekorServer
 	grpc_health_v1.UnimplementedHealthServer
-	storage  tessera.Storage
-	readOnly bool
+	storage           tessera.Storage
+	readOnly          bool
+	algorithmRegistry *signature.AlgorithmRegistryConfig
 }
 
-func NewServer(storage tessera.Storage, readOnly bool) *Server {
+func NewServer(storage tessera.Storage, readOnly bool, allowedKeyAlgorithms []string) (*Server, error) {
 	if readOnly {
 		return &Server{
 			readOnly: readOnly,
-		}
+		}, nil
 	}
-	return &Server{
-		storage: storage,
+	algorithmRegistry, err := algorithmRegistry(allowedKeyAlgorithms)
path: pkg/server/service.go
user: login: cmurphy
body: Done.
created_at: 2025-04-04T19:55:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -97,6 +98,14 @@ func verifyEnvelope(allPubKeyBytes map[*pb.Verifier][]byte, pbenv *pbdsse.Envelo
 			return nil, fmt.Errorf("could not parse public key as x509: %w", err)
 		}
 
+		valid, err := types.CheckEntryAlgorithms(key, alg, algorithmRegistry)
+		if err != nil {
+			return nil, fmt.Errorf("checking entry algorithm: %w", err)
+		}
+		if !valid {
+			return nil, fmt.Errorf("invalid entry algorithm")
path: pkg/types/dsse/dsse.go
user: login: cmurphy
body: I don't have a concise way to refer to the key but I can give the algorithm
created_at: 2025-04-04T20:00:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,64 @@
+// Copyright 2025 The Sigstore 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 server
+
+import (
+	"fmt"
+
+	v1 "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1"
+	"github.com/sigstore/sigstore/pkg/signature"
+)
+
+var (
+	AllowedClientSigningAlgorithms = []v1.PublicKeyDetails{
+		v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_2048_SHA256,
+		v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_3072_SHA256,
+		v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_4096_SHA256,
+		v1.PublicKeyDetails_PKIX_ECDSA_P256_SHA_256,
+		v1.PublicKeyDetails_PKIX_ECDSA_P384_SHA_384,
+		v1.PublicKeyDetails_PKIX_ECDSA_P521_SHA_512,
+		v1.PublicKeyDetails_PKIX_ED25519,
+		v1.PublicKeyDetails_PKIX_ED25519_PH,
+	}
+)
+
+// AlgorithmRegistry accepts a list of algorithms as strings, parses and formats them into a registry.
+func AlgorithmRegistry(algorithmOptions []string) (*signature.AlgorithmRegistryConfig, error) {
path: pkg/server/algorithmregistry.go
user: login: loosebazooka
body: I think this might need a test? But I'm okay if you add it in later to unblock any PRs waiting on this.
created_at: 2025-04-07T15:23:59Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,39 @@
+// Copyright 2025 The Sigstore 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 types
path: pkg/types/common.go
user: login: loosebazooka
body: should this and algorithimregistry.go live in their own package? They don't really need to be co-packaged with anything else?
created_at: 2025-04-07T15:26:09Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,39 @@
+// Copyright 2025 The Sigstore 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 types
path: pkg/types/common.go
user: login: cmurphy
body: done
created_at: 2025-04-07T19:59:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,64 @@
+// Copyright 2025 The Sigstore 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 server
+
+import (
+	"fmt"
+
+	v1 "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1"
+	"github.com/sigstore/sigstore/pkg/signature"
+)
+
+var (
+	AllowedClientSigningAlgorithms = []v1.PublicKeyDetails{
+		v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_2048_SHA256,
+		v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_3072_SHA256,
+		v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_4096_SHA256,
+		v1.PublicKeyDetails_PKIX_ECDSA_P256_SHA_256,
+		v1.PublicKeyDetails_PKIX_ECDSA_P384_SHA_384,
+		v1.PublicKeyDetails_PKIX_ECDSA_P521_SHA_512,
+		v1.PublicKeyDetails_PKIX_ED25519,
+		v1.PublicKeyDetails_PKIX_ED25519_PH,
+	}
+)
+
+// AlgorithmRegistry accepts a list of algorithms as strings, parses and formats them into a registry.
+func AlgorithmRegistry(algorithmOptions []string) (*signature.AlgorithmRegistryConfig, error) {
path: pkg/server/algorithmregistry.go
user: login: cmurphy
body: done
created_at: 2025-04-07T20:00:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -61,7 +62,7 @@ func ToLogEntry(ds *pb.DSSERequestV0_0_2) (*pb.DSSELogEntryV0_0_2, error) {
 			allPubKeyBytes[v] = cert.RawBytes
 		}
 	}
-	signerVerifiers, err := verifyEnvelope(allPubKeyBytes, ds.Envelope)
+	signerVerifiers, err := verifyEnvelope(allPubKeyBytes, ds.Envelope, crypto.SHA256, algorithmRegistry)
path: pkg/types/dsse/dsse.go
user: login: Hayden-IO
body: nit, can you add a TODO(https://github.com/sigstore/rekor-tiles/issues/176) for this
created_at: 2025-04-07T22:26:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -150,10 +152,36 @@ func TestToLogEntry(t *testing.T) {
 				Digest: hexDecodeOrDie(t, hexEncodedDigest),
 			},
 		},
+		{
+			name: "mismatched key algorithm",
+			hashedrekord: &pb.HashedRekordRequestV0_0_2{
+				Signature: &pb.Signature{
+					Content: b64DecodeOrDie(t, b64EncodedSignature),
+					Verifier: &pb.Verifier{
+						Verifier: &pb.Verifier_PublicKey{
+							PublicKey: &pb.PublicKey{
+								RawBytes: []byte(publicKey),
+							},
+						},
path: pkg/types/hashedrekord/hashedrekord_test.go
user: login: Hayden-IO
body: Can this test include `key_details` explicitly, since it missing is technically a malformed request? 
created_at: 2025-04-07T22:30:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -61,7 +62,7 @@ func ToLogEntry(ds *pb.DSSERequestV0_0_2) (*pb.DSSELogEntryV0_0_2, error) {
 			allPubKeyBytes[v] = cert.RawBytes
 		}
 	}
-	signerVerifiers, err := verifyEnvelope(allPubKeyBytes, ds.Envelope)
+	signerVerifiers, err := verifyEnvelope(allPubKeyBytes, ds.Envelope, crypto.SHA256, algorithmRegistry)
path: pkg/types/dsse/dsse.go
user: login: cmurphy
body: done
created_at: 2025-04-08T16:40:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -150,10 +152,36 @@ func TestToLogEntry(t *testing.T) {
 				Digest: hexDecodeOrDie(t, hexEncodedDigest),
 			},
 		},
+		{
+			name: "mismatched key algorithm",
+			hashedrekord: &pb.HashedRekordRequestV0_0_2{
+				Signature: &pb.Signature{
+					Content: b64DecodeOrDie(t, b64EncodedSignature),
+					Verifier: &pb.Verifier{
+						Verifier: &pb.Verifier_PublicKey{
+							PublicKey: &pb.PublicKey{
+								RawBytes: []byte(publicKey),
+							},
+						},
path: pkg/types/hashedrekord/hashedrekord_test.go
user: login: cmurphy
body: done
created_at: 2025-04-08T16:43:30Z
author_association: CONTRIBUTOR

PR comments:
user: login: codecov[bot]
created_at: 2025-03-27T23:06:51Z
body: ## [Codecov](https://app.codecov.io/gh/sigstore/rekor-tiles/pull/154?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) Report
Attention: Patch coverage is `41.11111%` with `53 lines` in your changes missing coverage. Please review.
> Project coverage is 32.50%. Comparing base [(`f8b1dc3`)](https://app.codecov.io/gh/sigstore/rekor-tiles/commit/f8b1dc322187c8f3344958a1fc93aa99bb95bf9d?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) to head [(`634fa6d`)](https://app.codecov.io/gh/sigstore/rekor-tiles/commit/634fa6dd39112872cadb100535bc90324358bc11?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore).
> Report is 2 commits behind head on main.

| [Files with missing lines](https://app.codecov.io/gh/sigstore/rekor-tiles/pull/154?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) | Patch % | Lines |
|---|---|---|
| [cmd/rekor-server/app/serve.go](https://app.codecov.io/gh/sigstore/rekor-tiles/pull/154?src=pr&el=tree&filepath=cmd%2Frekor-server%2Fapp%2Fserve.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore#diff-Y21kL3Jla29yLXNlcnZlci9hcHAvc2VydmUuZ28=) | 0.00% | [26 Missing :warning: ](https://app.codecov.io/gh/sigstore/rekor-tiles/pull/154?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) |
| [pkg/algorithmregistry/algorithmregistry.go](https://app.codecov.io/gh/sigstore/rekor-tiles/pull/154?src=pr&el=tree&filepath=pkg%2Falgorithmregistry%2Falgorithmregistry.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore#diff-cGtnL2FsZ29yaXRobXJlZ2lzdHJ5L2FsZ29yaXRobXJlZ2lzdHJ5Lmdv) | 48.57% | [16 Missing and 2 partials :warning: ](https://app.codecov.io/gh/sigstore/rekor-tiles/pull/154?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) |
| [pkg/types/hashedrekord/hashedrekord.go](https://app.codecov.io/gh/sigstore/rekor-tiles/pull/154?src=pr&el=tree&filepath=pkg%2Ftypes%2Fhashedrekord%2Fhashedrekord.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore#diff-cGtnL3R5cGVzL2hhc2hlZHJla29yZC9oYXNoZWRyZWtvcmQuZ28=) | 57.14% | [4 Missing and 2 partials :warning: ](https://app.codecov.io/gh/sigstore/rekor-tiles/pull/154?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) |
| [pkg/types/dsse/dsse.go](https://app.codecov.io/gh/sigstore/rekor-tiles/pull/154?src=pr&el=tree&filepath=pkg%2Ftypes%2Fdsse%2Fdsse.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore#diff-cGtnL3R5cGVzL2Rzc2UvZHNzZS5nbw==) | 70.00% | [2 Missing and 1 partial :warning: ](https://app.codecov.io/gh/sigstore/rekor-tiles/pull/154?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #154      +/-   ##
==========================================
+ Coverage   32.43%   32.50%   +0.06%     
==========================================
  Files          37       38       +1     
  Lines        3021     3101      +80     
==========================================
+ Hits          980     1008      +28     
- Misses       1948     1995      +47     
- Partials       93       98       +5     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/sigstore/rekor-tiles/pull/154?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: cmurphy
created_at: 2025-03-31T22:33:29Z
body: > Can we add this for DSSE too?

This is not as clear as I thought it would be, but maybe I'm missing something obvious: in our [old DSSE](https://github.com/sigstore/rekor/blob/main/pkg/types/dsse/v0.0.1/dsse_v0_0_1_schema.json) we had a `payloadHash` which included the message digest and hash algorithm, but in the [new one](https://github.com/sigstore/rekor-tiles/blob/main/api/proto/dsse.proto) we don't, so there's no way to check that the combination of the message hash algorithm and public key being used are valid as we do [here](https://github.com/sigstore/rekor/blob/267495348e4300ea331d0d5e2a51cbf4ec6241d2/pkg/api/entries.go#L271). There's nothing in the [DSSE spec](https://github.com/secure-systems-lab/dsse/blob/master/protocol.md) that suggests I should be able to find it in the envelope. Suggestions? Do we need to add `payloadHash` back to `DSSERequest`? Or should I assume sha256?
author_association: CONTRIBUTOR
user: login: cmurphy
created_at: 2025-04-01T16:09:36Z
body: Will skip DSSE for now.
author_association: CONTRIBUTOR
user: login: loosebazooka
created_at: 2025-04-02T20:10:39Z
body: @cmurphy would it be okay to wait on #144 before merging this?
author_association: MEMBER
user: login: Hayden-IO
created_at: 2025-04-08T16:45:46Z
body: @loosebazooka any more comments?
author_association: CONTRIBUTOR