• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / mender-artifact / 1998020591

22 Aug 2025 08:07AM UTC coverage: 76.088%. Remained the same
1998020591

push

gitlab-ci

web-flow
Merge pull request #734 from lluiscampos/update-codeowners-20250820-145040

QA-1017: chore(CODEOWNERS): Remove global ownership, add dependency files

5982 of 7862 relevant lines covered (76.09%)

137.68 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.99
/artifact/signer.go
1
// Copyright 2023 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14

15
package artifact
16

17
import (
18
        "crypto"
19
        "crypto/ecdsa"
20
        "crypto/rand"
21
        "crypto/rsa"
22
        "crypto/x509"
23
        "encoding/asn1"
24
        "encoding/base64"
25
        "encoding/pem"
26
        "math/big"
27

28
        "github.com/minio/sha256-simd"
29
        "github.com/pkg/errors"
30
)
31

32
// Signer is returning a signature of the provided message.
33
type Signer interface {
34
        Sign(message []byte) ([]byte, error)
35
}
36

37
// Verifier is verifying if provided message and signature matches.
38
type Verifier interface {
39
        Verify(message, sig []byte) error
40
}
41

42
// Crypto is an interface each specific signature algorithm must implement
43
// in order to be used with PKISigner.
44
type Crypto interface {
45
        Sign(message []byte, key interface{}) ([]byte, error)
46
        Verify(message, sig []byte, key interface{}) error
47
}
48

49
// RSA Crypto interface implementation
50
type RSA struct{}
51

52
func (r *RSA) Sign(message []byte, key interface{}) ([]byte, error) {
42✔
53
        var rsaKey *rsa.PrivateKey
42✔
54
        var ok bool
42✔
55

42✔
56
        // validate key
42✔
57
        if rsaKey, ok = key.(*rsa.PrivateKey); !ok {
44✔
58
                return nil, errors.New("signer: invalid private key")
2✔
59
        }
2✔
60

61
        h := sha256.Sum256(message)
40✔
62
        return rsa.SignPKCS1v15(rand.Reader, rsaKey, crypto.SHA256, h[:])
40✔
63
}
64

65
func (r *RSA) Verify(message, sig []byte, key interface{}) error {
27✔
66
        var rsaKey *rsa.PublicKey
27✔
67
        var ok bool
27✔
68

27✔
69
        // validate key
27✔
70
        if rsaKey, ok = key.(*rsa.PublicKey); !ok {
29✔
71
                return errors.New("signer: invalid rsa public key")
2✔
72
        }
2✔
73

74
        h := sha256.Sum256(message)
25✔
75
        return rsa.VerifyPKCS1v15(rsaKey, crypto.SHA256, h[:], sig)
25✔
76
}
77

78
// ECDSA Crypto interface implementation
79
const ecdsa256curveBits = 256
80
const ecdsa256keySize = 32
81
const ecdsa256Asn1SizeBytes = 70
82
const ecdsa256Asn1Padding = 2
83

84
type ECDSA256 struct{}
85

86
func (e *ECDSA256) Sign(message []byte, key interface{}) ([]byte, error) {
11✔
87
        var ecdsaKey *ecdsa.PrivateKey
11✔
88
        var ok bool
11✔
89

11✔
90
        // validate key
11✔
91
        if ecdsaKey, ok = key.(*ecdsa.PrivateKey); !ok {
13✔
92
                return nil, errors.New("signer: invalid private key")
2✔
93
        }
2✔
94

95
        // calculate the hash of the message to be signed
96
        h := sha256.Sum256(message)
9✔
97
        r, s, err := ecdsa.Sign(rand.Reader, ecdsaKey, h[:])
9✔
98
        if err != nil {
9✔
99
                return nil, errors.Wrap(err, "signer: error signing message")
×
100
        }
×
101
        // check if the size of the curve matches expected one;
102
        // for now we are supporting only 256 bit ecdsa
103
        if ecdsaKey.Curve.Params().BitSize != ecdsa256curveBits {
11✔
104
                return nil, errors.New("signer: invalid ecdsa curve size")
2✔
105
        }
2✔
106
        return MarshalECDSASignature(r, s)
7✔
107
}
108

109
func (e *ECDSA256) Verify(message, sig []byte, key interface{}) error {
18✔
110
        var ecdsaKey *ecdsa.PublicKey
18✔
111
        var ok bool
18✔
112

18✔
113
        // validate key
18✔
114
        if ecdsaKey, ok = key.(*ecdsa.PublicKey); !ok {
20✔
115
                return errors.New("signer: invalid ecdsa public key")
2✔
116
        }
2✔
117

118
        r, s, err := UnmarshalECDSASignature(sig)
16✔
119
        if err != nil {
21✔
120
                return err
5✔
121
        }
5✔
122

123
        h := sha256.Sum256(message)
11✔
124

11✔
125
        ok = ecdsa.Verify(ecdsaKey, h[:], r, s)
11✔
126
        if !ok {
15✔
127
                return errors.New("signer: verification failed")
4✔
128
        }
4✔
129
        return nil
7✔
130

131
}
132

133
func MarshalECDSASignature(r, s *big.Int) ([]byte, error) {
11✔
134
        // we serialize the r and s into one array where the first
11✔
135
        // half is the r and the other one s;
11✔
136
        // as both values are ecdsa256curveBits size we need
11✔
137
        // 2*ecdsa256keySize size slice to store both
11✔
138

11✔
139
        // MEN-1740 In some cases the size of the r and s can be different
11✔
140
        // than expected ecdsa256keySize. In this case we need to make sure
11✔
141
        // we are serializing those using correct offset. We can use leading
11✔
142
        // zeros easily as this has no impact on serializing and deserializing.
11✔
143
        rSize := len(r.Bytes())
11✔
144
        sSize := len(s.Bytes())
11✔
145
        if rSize > ecdsa256keySize || sSize > ecdsa256keySize {
11✔
146
                return nil,
×
147
                        errors.Errorf("signer: invalid size of ecdsa keys: r: %d; s: %d",
×
148
                                rSize, sSize)
×
149
        }
×
150

151
        // if the keys are shorter than expected we need to use correct offset
152
        // while serializing
153
        rOffset := ecdsa256keySize - rSize
11✔
154
        sOffset := ecdsa256keySize - sSize
11✔
155

11✔
156
        serialized := make([]byte, 2*ecdsa256keySize)
11✔
157
        copy(serialized[rOffset:], r.Bytes())
11✔
158
        copy(serialized[ecdsa256keySize+sOffset:], s.Bytes())
11✔
159

11✔
160
        return serialized, nil
11✔
161
}
162

163
func UnmarshalECDSASignature(sig []byte) (r, s *big.Int, e error) {
16✔
164
        // if the length of the signature is the double of key size, we know (and assume)
16✔
165
        // that it was us who created it via MarshalECDSASignature.
16✔
166
        // After the introduction of the hardware security support there is another possibility
16✔
167
        // (see below)
16✔
168
        if len(sig) == 2*ecdsa256keySize {
26✔
169
                return UnmarshalECDSASignatureMenderArtifact(sig)
10✔
170
        }
10✔
171

172
        // in case of a key supplied via PKCS#11 URI, we have no control over what the signature is
173
        // since it is designed to be actually verified via the same mechanism (PKCS#11 URI).
174
        // We know here that it is ECDSA key, and judging form the size we can assume
175
        // that it is ASN.1 encoded. If so, then it should be between 70 and 72 bytes.
176
        // In other words:
177
        // if the signature has not been created with MarshalECDSASignature, then we assume
178
        // it is to be decoded via ASN.1, with the protection on the signature length.
179
        if len(sig) >= ecdsa256Asn1SizeBytes &&
6✔
180
                len(sig) <= ecdsa256Asn1SizeBytes+ecdsa256Asn1Padding {
8✔
181
                return UnmarshalECDSASignatureASN1(sig)
2✔
182
        }
2✔
183
        return nil, nil, errors.Errorf("signer: invalid signature length: %d. "+
4✔
184
                "For ECDSA only P-256 is supported.", len(sig))
4✔
185
}
186

187
func UnmarshalECDSASignatureASN1(sig []byte) (r *big.Int, s *big.Int, err error) {
2✔
188
        var value asn1.RawValue
2✔
189
        _, err = asn1.Unmarshal(sig, &value)
2✔
190
        if err != nil {
2✔
191
                return nil, nil, errors.Wrap(err, "cannot unmarshal asn1 data")
×
192
        }
×
193
        bytesValue := value.Bytes
2✔
194
        if len(bytesValue) > 0 {
4✔
195
                var v asn1.RawValue
2✔
196
                bytesValue, err = asn1.Unmarshal(bytesValue, &v)
2✔
197
                if err != nil {
3✔
198
                        return nil, nil, errors.Wrap(err, "cannot unmarshal asn1 r value")
1✔
199
                }
1✔
200
                r = big.NewInt(0).SetBytes(v.Bytes)
1✔
201
        }
202
        if len(bytesValue) > 0 {
2✔
203
                var v asn1.RawValue
1✔
204
                _, err = asn1.Unmarshal(bytesValue, &v)
1✔
205
                if err != nil {
1✔
206
                        return nil, nil, errors.Wrap(err, "cannot unmarshal asn1 s value")
×
207
                }
×
208
                s = big.NewInt(0).SetBytes(v.Bytes)
1✔
209
        }
210
        return r, s, nil
1✔
211
}
212

213
func UnmarshalECDSASignatureMenderArtifact(sig []byte) (r *big.Int, s *big.Int, err error) {
10✔
214
        // get the signature; see corresponding `Sign` function for more details
10✔
215
        // about serialization
10✔
216
        r = big.NewInt(0).SetBytes(sig[:ecdsa256keySize])
10✔
217
        s = big.NewInt(0).SetBytes(sig[ecdsa256keySize:])
10✔
218
        return r, s, nil
10✔
219
}
10✔
220

221
type SigningMethod struct {
222
        // Key can be private or public depending if we want to sign or verify message
223
        Key    interface{}
224
        Public []byte
225
        Method Crypto
226
}
227

228
// PKISigner implements public-key encryption and supports X.509-encodded keys.
229
// For now both RSA and 256 bits ECDSA are supported.
230
type PKISigner struct {
231
        signMethod, verifyMethod *SigningMethod
232
}
233

234
func NewPKISigner(privateKey []byte) (*PKISigner, error) {
45✔
235
        if len(privateKey) == 0 {
45✔
236
                return nil, errors.New("signer: missing key")
×
237
        }
×
238
        signMethod, err := GetKeyAndSignMethod(privateKey)
45✔
239
        if err != nil {
45✔
240
                return nil, err
×
241
        }
×
242
        pub, err := x509.ParsePKIXPublicKey(signMethod.Public)
45✔
243
        if err != nil {
45✔
244
                return nil, errors.Wrap(err, "failed to parse encoded public key")
×
245
        }
×
246
        return &PKISigner{
45✔
247
                signMethod: signMethod,
45✔
248
                verifyMethod: &SigningMethod{
45✔
249
                        Key:    pub,
45✔
250
                        Method: signMethod.Method,
45✔
251
                },
45✔
252
        }, nil
45✔
253
}
254

255
func NewPKIVerifier(publicKey []byte) (*PKISigner, error) {
32✔
256
        if len(publicKey) == 0 {
33✔
257
                return nil, errors.New("signer: missing key")
1✔
258
        }
1✔
259
        verifyMethod, err := GetKeyAndVerifyMethod(publicKey)
31✔
260
        if err != nil {
35✔
261
                return nil, err
4✔
262
        }
4✔
263
        return &PKISigner{
27✔
264
                verifyMethod: verifyMethod,
27✔
265
        }, nil
27✔
266
}
267

268
func (s *PKISigner) Sign(message []byte) ([]byte, error) {
47✔
269
        if s.signMethod == nil {
47✔
270
                return nil, errors.New("signer: only verification allowed with this signer")
×
271
        }
×
272
        sig, err := s.signMethod.Method.Sign(message, s.signMethod.Key)
47✔
273
        if err != nil {
47✔
274
                return nil, errors.Wrap(err, "signer: error signing image")
×
275
        }
×
276
        enc := make([]byte, base64.StdEncoding.EncodedLen(len(sig)))
47✔
277
        base64.StdEncoding.Encode(enc, sig)
47✔
278
        return enc, nil
47✔
279
}
280

281
func (s *PKISigner) Verify(message, sig []byte) error {
28✔
282
        dec := make([]byte, base64.StdEncoding.DecodedLen(len(sig)))
28✔
283
        decLen, err := base64.StdEncoding.Decode(dec, sig)
28✔
284
        if err != nil {
28✔
285
                return errors.Wrap(err, "signer: error decoding signature")
×
286
        }
×
287

288
        if s.verifyMethod == nil {
28✔
289
                return errors.New("verifyMethod is nil")
×
290
        }
×
291
        if s.verifyMethod.Method == nil {
28✔
292
                return errors.New("verifyMethod.Method is nil")
×
293
        }
×
294

295
        return s.verifyMethod.Method.Verify(message, dec[:decLen], s.verifyMethod.Key)
28✔
296
}
297

298
func GetPublic(private []byte) ([]byte, error) {
×
299
        sm, err := GetKeyAndSignMethod(private)
×
300
        if err != nil {
×
301
                return nil, errors.Wrap(err, "signer: error parsing private key")
×
302
        }
×
303
        return sm.Public, nil
×
304
}
305

306
func GetKeyAndVerifyMethod(keyPEM []byte) (*SigningMethod, error) {
60✔
307
        block, _ := pem.Decode(keyPEM)
60✔
308
        if block == nil {
65✔
309
                return nil, errors.New("signer: failed to parse public key")
5✔
310
        }
5✔
311

312
        pub, err := x509.ParsePKIXPublicKey(block.Bytes)
55✔
313
        if err != nil {
58✔
314
                return nil, errors.Wrap(err, "failed to parse encoded public key")
3✔
315
        }
3✔
316
        switch pub := pub.(type) {
52✔
317
        case *rsa.PublicKey:
31✔
318
                return &SigningMethod{Key: pub, Method: new(RSA)}, nil
31✔
319
        case *ecdsa.PublicKey:
19✔
320
                return &SigningMethod{Key: pub, Method: new(ECDSA256)}, nil
19✔
321
        default:
2✔
322
                return nil, errors.Errorf("unsupported public key type: %v", pub)
2✔
323
        }
324
}
325

326
func GetKeyAndSignMethod(keyPEM []byte) (*SigningMethod, error) {
67✔
327
        block, _ := pem.Decode(keyPEM)
67✔
328
        if block == nil {
69✔
329
                return nil, errors.New("signer: failed to parse private key")
2✔
330
        }
2✔
331

332
        rsaKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
65✔
333
        if err == nil {
113✔
334
                pub, keyErr := x509.MarshalPKIXPublicKey(rsaKey.Public())
48✔
335
                if keyErr != nil {
48✔
336
                        return nil, errors.Wrap(err, "signer: can not extract public RSA key")
×
337
                }
×
338
                return &SigningMethod{Key: rsaKey, Public: pub, Method: new(RSA)}, nil
48✔
339
        }
340

341
        ecdsaKey, err := x509.ParseECPrivateKey(block.Bytes)
17✔
342
        if err == nil {
32✔
343
                pub, keyErr := x509.MarshalPKIXPublicKey(ecdsaKey.Public())
15✔
344
                if keyErr != nil {
15✔
345
                        return nil, errors.Wrap(err, "signer: can not extract public ECDSA key")
×
346
                }
×
347
                return &SigningMethod{Key: ecdsaKey, Public: pub, Method: new(ECDSA256)}, nil
15✔
348
        }
349

350
        key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
2✔
351
        if ecdsaKey, ok := key.(*ecdsa.PrivateKey); ok {
2✔
352
                if err == nil {
×
353
                        pub, keyErr := x509.MarshalPKIXPublicKey(ecdsaKey.Public())
×
354
                        if keyErr != nil {
×
355
                                return nil, errors.Wrap(err, "signer: can not extract public ECDSA key")
×
356
                        }
×
357
                        return &SigningMethod{Key: ecdsaKey, Public: pub, Method: new(ECDSA256)}, nil
×
358
                }
359
        }
360

361
        if rsaKey, ok := key.(*rsa.PrivateKey); ok {
2✔
362
                if err == nil {
×
363
                        pub, keyErr := x509.MarshalPKIXPublicKey(rsaKey.Public())
×
364
                        if keyErr != nil {
×
365
                                return nil, errors.Wrap(err, "signer: can not extract public RSA key")
×
366
                        }
×
367
                        return &SigningMethod{Key: rsaKey, Public: pub, Method: new(RSA)}, nil
×
368
                }
369
        }
370

371
        if err == nil {
2✔
372
                err = errors.New("unsupported private key type")
×
373
        }
×
374

375
        return nil, errors.Wrap(err, "signer: unsupported private key type or error occurred")
2✔
376
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc