-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsign.go
162 lines (134 loc) · 3.13 KB
/
sign.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
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// Copyright 2024 Contributors to the Veraison project.
// SPDX-License-Identifier: Apache-2.0
package main
import (
"crypto"
"crypto/rand"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rsa"
"strings"
"errors"
"fmt"
"reflect"
cose "github.com/veraison/go-cose"
"github.com/lestrrat-go/jwx/v2/jwk"
)
const (
HeaderLabelMeta = int64(8)
noAlg = cose.Algorithm(-65537)
)
func coseSignerFromJWK(j []byte) (cose.Signer, error) {
alg, key, err := getAlgAndKeyFromJWK(j)
if err != nil {
return nil, err
}
return cose.NewSigner(alg, key)
}
func getAlgAndKeyFromJWK(j []byte) (cose.Algorithm, crypto.Signer, error) {
var (
err error
k jwk.Key
crv elliptic.Curve
alg cose.Algorithm
)
k, err = jwk.ParseKey(j)
if err != nil {
return noAlg, nil, err
}
var key crypto.Signer
err = k.Raw(&key)
if err != nil {
return noAlg, nil, err
}
switch v := key.(type) {
case *ecdsa.PrivateKey:
alg = ellipticCurveToAlg(v.Curve)
if alg == noAlg {
return noAlg, nil, fmt.Errorf("unknown elliptic curve %v", crv)
}
case ed25519.PrivateKey:
alg = cose.AlgorithmEd25519
case *rsa.PrivateKey:
alg = rsaJWKToAlg(k)
if alg == noAlg {
return noAlg, nil, fmt.Errorf("unknown RSA algorithm %q", k.Algorithm().String())
}
default:
return noAlg, nil, fmt.Errorf("unknown private key type %v", reflect.TypeOf(key))
}
return alg, key, nil
}
func getKidFromJWK(j []byte) ([]byte, error) {
k, err := jwk.ParseKey(j)
if err != nil {
return nil, err
}
if len(k.KeyID()) != 0 {
return []byte(k.KeyID()), nil
}
// Generate a key ID from the JWK Thumbprint if none exist
// See https://datatracker.ietf.org/doc/html/rfc7638
kid, err := k.Thumbprint(crypto.SHA256)
if err != nil {
return nil, err
}
return kid, nil
}
func ellipticCurveToAlg(c elliptic.Curve) cose.Algorithm {
switch c {
case elliptic.P256():
return cose.AlgorithmES256
case elliptic.P384():
return cose.AlgorithmES384
case elliptic.P521():
return cose.AlgorithmES512
default:
return noAlg
}
}
func rsaJWKToAlg(k jwk.Key) cose.Algorithm {
switch k.Algorithm().String() {
case "PS256":
return cose.AlgorithmPS256
case "PS384":
return cose.AlgorithmPS384
case "PS512":
return cose.AlgorithmPS512
default:
return noAlg
}
}
func sign(
payload []byte,
meta []byte,
contentType string,
kid []byte,
signer cose.Signer,
) ([]byte, error) {
if signer == nil {
return nil, errors.New("nil signer")
}
message := cose.NewSign1Message()
message.Payload = payload
alg := signer.Algorithm()
if strings.Contains(alg.String(), "unknown algorithm value") {
return nil, errors.New("signer has no algorithm")
}
message.Headers.Protected.SetAlgorithm(alg)
message.Headers.Protected[cose.HeaderLabelContentType] = contentType
message.Headers.Protected[cose.HeaderLabelKeyID] = kid
if meta != nil {
message.Headers.Protected[HeaderLabelMeta] = meta
}
err := message.Sign(rand.Reader, []byte(""), signer)
if err != nil {
return nil, fmt.Errorf("COSE Sign1 signature failed: %w", err)
}
wrap, err := message.MarshalCBOR()
if err != nil {
return nil, fmt.Errorf("signed-corim marshaling failed: %w", err)
}
return wrap, nil
}