Skip to content

Commit ee1f9ae

Browse files
committed
Added --client-signing-algorithms flag
Signed-off-by: Riccardo Schirone <[email protected]>
1 parent 9865ca9 commit ee1f9ae

File tree

3 files changed

+166
-3
lines changed

3 files changed

+166
-3
lines changed

cmd/rekor-server/app/root.go

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,25 @@ import (
2020
"net/http"
2121
"net/http/pprof"
2222
"os"
23+
"sort"
24+
"strings"
2325
"time"
2426

2527
homedir "github.com/mitchellh/go-homedir"
28+
v1 "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1"
2629
"github.com/sigstore/rekor/pkg/log"
30+
"github.com/sigstore/sigstore/pkg/signature"
2731
"github.com/spf13/cobra"
2832
"github.com/spf13/viper"
2933

3034
"sigs.k8s.io/release-utils/version"
3135
)
3236

3337
var (
34-
cfgFile string
35-
logType string
36-
enablePprof bool
38+
cfgFile string
39+
logType string
40+
enablePprof bool
41+
clientSigningAlgorithms ClientSigningAlgorithmOptions
3742
// these map to the operationId as defined in openapi.yaml file
3843
operationIds = []string{
3944
"searchIndex",
@@ -68,6 +73,64 @@ func Execute() {
6873
}
6974
}
7075

76+
type ClientSigningAlgorithmOptions []v1.KnownSignatureAlgorithm
77+
78+
func (sa *ClientSigningAlgorithmOptions) String() string {
79+
var algos []v1.KnownSignatureAlgorithm
80+
if len(*sa) == 0 {
81+
algos = []v1.KnownSignatureAlgorithm{}
82+
for keyAlgorithmId := range v1.KnownSignatureAlgorithm_name {
83+
if keyAlgorithmId == 0 {
84+
continue
85+
}
86+
algos = append(algos, v1.KnownSignatureAlgorithm(keyAlgorithmId))
87+
}
88+
} else {
89+
algos = []v1.KnownSignatureAlgorithm(*sa)
90+
}
91+
algos_str := []string{}
92+
for _, algo := range algos {
93+
algo_str, err := signature.FormatSignatureAlgorithmFlag(algo)
94+
if err != nil {
95+
panic(err)
96+
}
97+
algos_str = append(algos_str, *algo_str)
98+
}
99+
return strings.Join(algos_str, ",")
100+
}
101+
102+
func (sa *ClientSigningAlgorithmOptions) Set(s string) error {
103+
algos := strings.Split(s, ",")
104+
options := []v1.KnownSignatureAlgorithm{}
105+
for _, algo := range algos {
106+
signatureAlgorithm, err := signature.ParseSignatureAlgorithmFlag(algo)
107+
if err != nil {
108+
return err
109+
}
110+
options = append(options, signatureAlgorithm)
111+
}
112+
*sa = ClientSigningAlgorithmOptions(options)
113+
return nil
114+
}
115+
116+
func (sa *ClientSigningAlgorithmOptions) Type() string {
117+
return "stringSlice"
118+
}
119+
120+
func (sa *ClientSigningAlgorithmOptions) Value() []v1.KnownSignatureAlgorithm {
121+
if len(*sa) == 0 {
122+
algos := []v1.KnownSignatureAlgorithm{}
123+
for keyAlgorithmId := range v1.KnownSignatureAlgorithm_name {
124+
if keyAlgorithmId == 0 {
125+
continue
126+
}
127+
algos = append(algos, v1.KnownSignatureAlgorithm(keyAlgorithmId))
128+
}
129+
return algos
130+
}
131+
return []v1.KnownSignatureAlgorithm(*sa)
132+
}
133+
71134
func init() {
72135
cobra.OnInitialize(initConfig)
73136

@@ -131,6 +194,21 @@ Memory and file-based signers should only be used for testing.`)
131194
rootCmd.PersistentFlags().Int("search_index.mysql.max_open_connections", 0, "maximum open connections")
132195
rootCmd.PersistentFlags().Int("search_index.mysql.max_idle_connections", 0, "maximum idle connections")
133196

197+
keyAlgorithmTypes := []string{}
198+
for keyAlgorithmId := range v1.KnownSignatureAlgorithm_name {
199+
if keyAlgorithmId == 0 {
200+
continue
201+
}
202+
keyFlag, err := signature.FormatSignatureAlgorithmFlag(v1.KnownSignatureAlgorithm(keyAlgorithmId))
203+
if err != nil {
204+
panic(err)
205+
}
206+
keyAlgorithmTypes = append(keyAlgorithmTypes, *keyFlag)
207+
}
208+
sort.Strings(keyAlgorithmTypes)
209+
keyAlgorithmHelp := fmt.Sprintf("signing algorithm to use for signing/hashing (allowed %s)", strings.Join(keyAlgorithmTypes, ", "))
210+
rootCmd.PersistentFlags().Var(&clientSigningAlgorithms, "client-signing-algorithms", keyAlgorithmHelp)
211+
134212
if err := viper.BindPFlags(rootCmd.PersistentFlags()); err != nil {
135213
log.Logger.Fatal(err)
136214
}

pkg/api/api.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"google.golang.org/grpc"
3131
"google.golang.org/grpc/credentials/insecure"
3232

33+
v1 "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1"
3334
"github.com/sigstore/rekor/pkg/indexstorage"
3435
"github.com/sigstore/rekor/pkg/log"
3536
"github.com/sigstore/rekor/pkg/pubsub"
@@ -70,6 +71,7 @@ type API struct {
7071
// Publishes notifications when new entries are added to the log. May be
7172
// nil if no publisher is configured.
7273
newEntryPublisher pubsub.Publisher
74+
algorithmRegistry *signature.AlgorithmRegistryConfig
7375
}
7476

7577
func NewAPI(treeID uint) (*API, error) {
@@ -102,6 +104,20 @@ func NewAPI(treeID uint) (*API, error) {
102104
log.Logger.Infof("Starting Rekor server with active tree %v", tid)
103105
ranges.SetActive(tid)
104106

107+
algorithms_str := viper.GetStringSlice("client-signing-algorithms")
108+
var algorithms []v1.KnownSignatureAlgorithm
109+
for _, a := range algorithms_str {
110+
algorithm, err := signature.ParseSignatureAlgorithmFlag(a)
111+
if err != nil {
112+
return nil, fmt.Errorf("parsing signature algorithm flag: %w", err)
113+
}
114+
algorithms = append(algorithms, algorithm)
115+
}
116+
algorithmRegistry, err := signature.NewAlgorithmRegistryConfig(algorithms)
117+
if err != nil {
118+
return nil, fmt.Errorf("getting algorithm registry: %w", err)
119+
}
120+
105121
rekorSigner, err := signer.New(ctx, viper.GetString("rekor_server.signer"),
106122
viper.GetString("rekor_server.signer-passwd"))
107123
if err != nil {
@@ -142,6 +158,7 @@ func NewAPI(treeID uint) (*API, error) {
142158
signer: rekorSigner,
143159
// Utility functionality not required for operation of the core service
144160
newEntryPublisher: newEntryPublisher,
161+
algorithmRegistry: algorithmRegistry,
145162
}, nil
146163
}
147164

pkg/api/entries.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,17 @@ package api
1818
import (
1919
"bytes"
2020
"context"
21+
"crypto"
22+
"crypto/ecdsa"
23+
"crypto/ed25519"
24+
"crypto/rsa"
25+
"crypto/x509"
2126
"encoding/hex"
2227
"errors"
2328
"fmt"
2429
"net/http"
2530
"net/url"
31+
"strings"
2632

2733
"github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer"
2834
"github.com/go-openapi/runtime"
@@ -177,12 +183,74 @@ func GetLogEntryByIndexHandler(params entries.GetLogEntryByIndexParams) middlewa
177183
return entries.NewGetLogEntryByIndexOK().WithPayload(logEntry)
178184
}
179185

186+
func checkEntryAlgorithms(entry types.EntryImpl) (bool, error) {
187+
verifiers, err := entry.Verifiers()
188+
if err != nil {
189+
return false, fmt.Errorf("getting verifiers: %w", err)
190+
}
191+
// Get artifact hash from entry
192+
artifactHash, err := entry.ArtifactHash()
193+
if err != nil {
194+
return false, fmt.Errorf("getting artifact hash: %w", err)
195+
}
196+
artifactHashAlgorithm := artifactHash[:strings.Index(artifactHash, ":")]
197+
var artifactHashValue crypto.Hash
198+
switch artifactHashAlgorithm {
199+
case "sha256":
200+
artifactHashValue = crypto.SHA256
201+
case "sha384":
202+
artifactHashValue = crypto.SHA384
203+
case "sha512":
204+
artifactHashValue = crypto.SHA512
205+
default:
206+
return false, fmt.Errorf("unsupported artifact hash algorithm %s", artifactHashAlgorithm)
207+
}
208+
209+
// Check if all the verifiers public keys (together with the ArtifactHash)
210+
// are allowed according to the policy
211+
for _, v := range verifiers {
212+
identities, err := v.Identities()
213+
if err != nil {
214+
return false, fmt.Errorf("getting identities: %w", err)
215+
}
216+
217+
for _, identity := range identities {
218+
var publicKey crypto.PublicKey
219+
switch identityCrypto := identity.Crypto.(type) {
220+
case *x509.Certificate:
221+
publicKey = identityCrypto.PublicKey
222+
case *rsa.PublicKey:
223+
publicKey = identityCrypto
224+
case *ecdsa.PublicKey:
225+
publicKey = identityCrypto
226+
case ed25519.PublicKey:
227+
publicKey = identityCrypto
228+
default:
229+
continue
230+
}
231+
if !api.algorithmRegistry.IsAlgorithmPermitted(publicKey, artifactHashValue) {
232+
return false, nil
233+
}
234+
}
235+
}
236+
return true, nil
237+
}
238+
180239
func createLogEntry(params entries.CreateLogEntryParams) (models.LogEntry, middleware.Responder) {
181240
ctx := params.HTTPRequest.Context()
182241
entry, err := types.CreateVersionedEntry(params.ProposedEntry)
183242
if err != nil {
184243
return nil, handleRekorAPIError(params, http.StatusBadRequest, err, fmt.Sprintf(validationError, err))
185244
}
245+
246+
areEntryAlgorithmsAllowed, err := checkEntryAlgorithms(entry)
247+
if err != nil {
248+
return nil, handleRekorAPIError(params, http.StatusBadRequest, err, fmt.Sprintf(validationError, err))
249+
}
250+
if !areEntryAlgorithmsAllowed {
251+
return nil, handleRekorAPIError(params, http.StatusBadRequest, errors.New("entry algorithms are not allowed"), fmt.Sprintf(validationError, "entry algorithms are not allowed"))
252+
}
253+
186254
leaf, err := types.CanonicalizeEntry(ctx, entry)
187255
if err != nil {
188256
if _, ok := (err).(types.ValidationError); ok {

0 commit comments

Comments
 (0)