-
Notifications
You must be signed in to change notification settings - Fork 9
/
ecdsa_verifier.go
118 lines (101 loc) · 3.62 KB
/
ecdsa_verifier.go
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
// Copyright 2024 Thales Group
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package gose
import (
"bytes"
"crypto/ecdsa"
"crypto/x509"
"encoding/pem"
"math/big"
"github.com/ThalesGroup/gose/jose"
"github.com/sirupsen/logrus"
)
// ECVerificationKeyImpl implements the ECDSA Verification Logic
type ECVerificationKeyImpl struct {
key ecdsa.PublicKey
jwk jose.Jwk
}
const ecPublicKeyPemType = "EC PUBLIC KEY"
// Algorithm return algorithm
func (verifier *ECVerificationKeyImpl) Algorithm() jose.Alg {
return verifier.jwk.Alg()
}
// Verify signed data matches signature and jwk
// The input signature is encoded as r || s which is different to the standard go crypto interface specification.
// The serialization format is chosen instead to match that defined in the JSON Web Signature spec
// https://tools.ietf.org/html/rfc7515#appendix-A.3.1.
func (verifier *ECVerificationKeyImpl) Verify(operation jose.KeyOps, data []byte, signature []byte) bool {
ops := intersection(validVerificationOps, verifier.jwk.Ops())
if !isSubset(ops, []jose.KeyOps{operation}) {
return false
}
// Get the key
ecdsaKey := verifier.key
opts := algToOptsMap[verifier.Algorithm()].(*ECDSAOptions)
keySize := opts.keySizeBytes
if len(signature) != 2*keySize {
return false
}
r := big.NewInt(0).SetBytes(signature[:keySize])
s := big.NewInt(0).SetBytes(signature[keySize:])
// Create hasher
if !opts.Hash.Available() {
return false
}
hasher := opts.HashFunc().New()
if _, err := hasher.Write([]byte(data)); err != nil {
logrus.Panicf("%s", err)
}
// Verify the signature
return ecdsa.Verify(&ecdsaKey, hasher.Sum(nil), r, s)
}
// Certificates returns the certs for this key
func (verifier *ECVerificationKeyImpl) Certificates() []*x509.Certificate {
return verifier.jwk.X5C()
}
// Jwk returns the key as a jose.JWK type, or error
func (verifier *ECVerificationKeyImpl) Jwk() (jose.Jwk, error) {
return verifier.jwk, nil
}
// Marshal marshals the key into a compact JWK string, or error
func (verifier *ECVerificationKeyImpl) Marshal() (string, error) {
return JwkToString(verifier.jwk)
}
// MarshalPem marshals the key as a PEM formatted string, or error
func (verifier *ECVerificationKeyImpl) MarshalPem() (string, error) {
derEncoded, err := x509.MarshalPKIXPublicKey(&verifier.key)
if err != nil {
return "", err
}
block := pem.Block{
Type: ecPublicKeyPemType,
Bytes: derEncoded,
}
output := bytes.Buffer{}
if err := pem.Encode(&output, &block); err != nil {
return "", err
}
return string(output.Bytes()), nil
}
//Kid returns the key's id
func (verifier *ECVerificationKeyImpl) Kid() string {
return verifier.jwk.Kid()
}