File: signer.go

package info (click to toggle)
golang-github-sigstore-sigstore 1.9.5-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 2,052 kB
  • sloc: makefile: 87; sh: 45
file content (147 lines) | stat: -rw-r--r-- 5,082 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//
// Copyright 2021 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 signature

import (
	"crypto"
	"crypto/ecdsa"
	"crypto/ed25519"
	"crypto/rsa"
	"errors"
	"io"
	"os"
	"path/filepath"

	// these ensure we have the implementations loaded
	_ "crypto/sha256"
	_ "crypto/sha512"

	"github.com/sigstore/sigstore/pkg/cryptoutils"
	"github.com/sigstore/sigstore/pkg/signature/options"

	// these ensure we have the implementations loaded
	_ "golang.org/x/crypto/sha3"
)

// Signer creates digital signatures over a message using a specified key pair
type Signer interface {
	PublicKeyProvider
	SignMessage(message io.Reader, opts ...SignOption) ([]byte, error)
}

// SignerOpts implements crypto.SignerOpts but also allows callers to specify
// additional options that may be utilized in signing the digest provided.
type SignerOpts struct {
	Hash crypto.Hash
	Opts []SignOption
}

// HashFunc returns the hash function for this object
func (s SignerOpts) HashFunc() crypto.Hash {
	return s.Hash
}

// LoadSigner returns a signature.Signer based on the algorithm of the private key
// provided.
//
// If privateKey is an RSA key, a RSAPKCS1v15Signer will be returned. If a
// RSAPSSSigner is desired instead, use the LoadRSAPSSSigner() method directly.
func LoadSigner(privateKey crypto.PrivateKey, hashFunc crypto.Hash) (Signer, error) {
	return LoadSignerWithOpts(privateKey, options.WithHash(hashFunc))
}

// LoadSignerWithOpts returns a signature.Signer based on the algorithm of the private key
// provided.
func LoadSignerWithOpts(privateKey crypto.PrivateKey, opts ...LoadOption) (Signer, error) {
	var rsaPSSOptions *rsa.PSSOptions
	var useED25519ph bool
	hashFunc := crypto.SHA256
	for _, o := range opts {
		o.ApplyED25519ph(&useED25519ph)
		o.ApplyHash(&hashFunc)
		o.ApplyRSAPSS(&rsaPSSOptions)
	}

	switch pk := privateKey.(type) {
	case *rsa.PrivateKey:
		if rsaPSSOptions != nil {
			return LoadRSAPSSSigner(pk, hashFunc, rsaPSSOptions)
		}
		return LoadRSAPKCS1v15Signer(pk, hashFunc)
	case *ecdsa.PrivateKey:
		return LoadECDSASigner(pk, hashFunc)
	case ed25519.PrivateKey:
		if useED25519ph {
			return LoadED25519phSigner(pk)
		}
		return LoadED25519Signer(pk)
	}
	return nil, errors.New("unsupported public key type")
}

// LoadSignerFromPEMFile returns a signature.Signer based on the algorithm of the private key
// in the file. The Signer will use the hash function specified when computing digests.
//
// If key is an RSA key, a RSAPKCS1v15Signer will be returned. If a
// RSAPSSSigner is desired instead, use the LoadRSAPSSSigner() and
// cryptoutils.UnmarshalPEMToPrivateKey() methods directly.
func LoadSignerFromPEMFile(path string, hashFunc crypto.Hash, pf cryptoutils.PassFunc) (Signer, error) {
	fileBytes, err := os.ReadFile(filepath.Clean(path))
	if err != nil {
		return nil, err
	}
	priv, err := cryptoutils.UnmarshalPEMToPrivateKey(fileBytes, pf)
	if err != nil {
		return nil, err
	}
	return LoadSigner(priv, hashFunc)
}

// LoadSignerFromPEMFileWithOpts returns a signature.Signer based on the algorithm of the private key
// in the file. The Signer will use the hash function specified in the options when computing digests.
func LoadSignerFromPEMFileWithOpts(path string, pf cryptoutils.PassFunc, opts ...LoadOption) (Signer, error) {
	fileBytes, err := os.ReadFile(filepath.Clean(path))
	if err != nil {
		return nil, err
	}
	priv, err := cryptoutils.UnmarshalPEMToPrivateKey(fileBytes, pf)
	if err != nil {
		return nil, err
	}
	return LoadSignerWithOpts(priv, opts...)
}

// LoadDefaultSigner returns a signature.Signer based on the private key.
// Each private key has a corresponding PublicKeyDetails associated in the
// Sigstore ecosystem, see Algorithm Registry for more details.
func LoadDefaultSigner(privateKey crypto.PrivateKey, opts ...LoadOption) (Signer, error) {
	signer, ok := privateKey.(crypto.Signer)
	if !ok {
		return nil, errors.New("private key does not implement signature.Signer")
	}
	algorithmDetails, err := GetDefaultAlgorithmDetails(signer.Public(), opts...)
	if err != nil {
		return nil, err
	}
	return LoadSignerFromAlgorithmDetails(privateKey, algorithmDetails, opts...)
}

// LoadSignerFromAlgorithmDetails returns a signature.Signer based on
// the algorithm details and the user's choice of options.
func LoadSignerFromAlgorithmDetails(privateKey crypto.PrivateKey, algorithmDetails AlgorithmDetails, opts ...LoadOption) (Signer, error) {
	filteredOpts := GetOptsFromAlgorithmDetails(algorithmDetails, opts...)
	return LoadSignerWithOpts(privateKey, filteredOpts...)
}