@@ -18,15 +18,20 @@ import (
18
18
"bytes"
19
19
"context"
20
20
"crypto"
21
+ "crypto/ecdsa"
22
+ "crypto/elliptic"
23
+ "crypto/x509"
21
24
"encoding/hex"
22
25
"errors"
23
26
"fmt"
24
27
"hash"
25
28
"io"
29
+ "os"
26
30
"slices"
27
31
28
32
in_toto "github.com/in-toto/attestation/go/v1"
29
33
"github.com/secure-systems-lab/go-securesystemslib/dsse"
34
+ v1 "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1"
30
35
"github.com/sigstore/sigstore-go/pkg/root"
31
36
"github.com/sigstore/sigstore/pkg/signature"
32
37
sigdsse "github.com/sigstore/sigstore/pkg/signature/dsse"
@@ -104,15 +109,84 @@ func VerifySignatureWithArtifactDigests(sigContent SignatureContent, verificatio
104
109
return verifyEnvelopeWithArtifactDigests (verifier , envelope , digests )
105
110
}
106
111
112
+ // compatVerifier is a signature.Verifier that tries multiple verifiers
113
+ // and returns nil if any of them verify the signature. This is used to
114
+ // verify signatures that were generated with old clients that used SHA256
115
+ // for ECDSA P384/P521 keys.
116
+ type compatVerifier struct {
117
+ verifiers []signature.Verifier
118
+ }
119
+
120
+ func (v * compatVerifier ) VerifySignature (signature , message io.Reader , opts ... signature.VerifyOption ) error {
121
+ for idx , verifier := range v .verifiers {
122
+ if idx != 0 {
123
+ fmt .Fprint (os .Stderr , "Failed to verify signature with default verifier, trying compatibility verifier\n " )
124
+ // Reset the signature and message readers to the beginning so they can be reused
125
+ seeker , ok := signature .(io.Seeker )
126
+ if ok {
127
+ seeker .Seek (0 , 0 )
128
+ }
129
+ seeker , ok = message .(io.Seeker )
130
+ if ok {
131
+ seeker .Seek (0 , 0 )
132
+ }
133
+ }
134
+ err := verifier .VerifySignature (signature , message , opts ... )
135
+ if err == nil {
136
+ return nil
137
+ }
138
+ }
139
+ return fmt .Errorf ("no compatible verifier found" )
140
+ }
141
+
142
+ func (v * compatVerifier ) PublicKey (opts ... signature.PublicKeyOption ) (crypto.PublicKey , error ) {
143
+ return v .verifiers [0 ].PublicKey (opts ... )
144
+ }
145
+
146
+ func compatSignatureVerifier (leafCert * x509.Certificate ) (signature.Verifier , error ) {
147
+ // LoadDefaultSigner/Verifier functions accept a few options to select
148
+ // the default signer/verifier when there are ambiguities, like for
149
+ // ED25519 keys, which could be used with PureEd25519 or Ed25519ph.
150
+ //
151
+ // Pass `WithED25519ph()` to select Ed25519ph by default, when ED25519
152
+ // key is found, because for hashedrekord entries this is the only option.
153
+ defaultOpts := []signature.LoadOption {options .WithED25519ph ()}
154
+
155
+ verifiers := make ([]signature.Verifier , 0 )
156
+ verifier , err := signature .LoadDefaultVerifier (leafCert .PublicKey , defaultOpts ... )
157
+ if err != nil {
158
+ return nil , err
159
+ }
160
+ verifiers = append (verifiers , verifier )
161
+
162
+ // Add a compatibility verifier for ECDSA P384/P521, because we still want
163
+ // to verify signatures generated with old clients that used SHA256
164
+ switch leafCert .PublicKey .(type ) {
165
+ case * ecdsa.PublicKey :
166
+ var algorithmDetails signature.AlgorithmDetails
167
+ switch leafCert .PublicKey .(* ecdsa.PublicKey ).Curve {
168
+ case elliptic .P384 ():
169
+ algorithmDetails , err = signature .GetAlgorithmDetails (v1 .PublicKeyDetails_PKIX_ECDSA_P384_SHA_256 )
170
+ case elliptic .P521 ():
171
+ algorithmDetails , err = signature .GetAlgorithmDetails (v1 .PublicKeyDetails_PKIX_ECDSA_P521_SHA_256 )
172
+ default :
173
+ return verifier , nil
174
+ }
175
+ if err != nil {
176
+ return nil , err
177
+ }
178
+ verifier , err = signature .LoadVerifierFromAlgorithmDetails (leafCert .PublicKey , algorithmDetails , defaultOpts ... )
179
+ if err != nil {
180
+ return nil , err
181
+ }
182
+ verifiers = append (verifiers , verifier )
183
+ }
184
+ return & compatVerifier {verifiers : verifiers }, nil
185
+ }
186
+
107
187
func getSignatureVerifier (verificationContent VerificationContent , tm root.TrustedMaterial ) (signature.Verifier , error ) {
108
188
if leafCert := verificationContent .Certificate (); leafCert != nil {
109
- // LoadDefaultSigner/Verifier functions accept a few options to select
110
- // the default signer/verifier when there are ambiguities, like for
111
- // ED25519 keys, which could be used with PureEd25519 or Ed25519ph.
112
- //
113
- // Pass `WithED25519ph()` to select Ed25519ph by default, when ED25519
114
- // key is found, because for hashedrekord entries this is the only option.
115
- return signature .LoadDefaultVerifier (leafCert .PublicKey , options .WithED25519ph ())
189
+ return compatSignatureVerifier (leafCert )
116
190
} else if pk := verificationContent .PublicKey (); pk != nil {
117
191
return tm .PublicKeyVerifier (pk .Hint ())
118
192
}
0 commit comments