-
Notifications
You must be signed in to change notification settings - Fork 2
/
util_normalize.go
108 lines (96 loc) · 2.84 KB
/
util_normalize.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
package jwk
import (
"crypto/ecdsa"
"crypto/rsa"
"encoding/base64"
"errors"
"fmt"
"hash"
"github.com/rakutentech/jwk-go/okp"
)
func getKeyAlgo(key interface{}, sig bool) string {
switch k := key.(type) {
case *ecdsa.PrivateKey, *ecdsa.PublicKey:
if sig {
return DefaultECSignAlg
} else if UseKeyWrapForECDH {
return DefaultECKeyAlgWithKeyWrap
} else {
return DefaultECKeyAlg
}
case *rsa.PrivateKey, *rsa.PublicKey:
if sig {
return DefaultRSASignAlg
}
return DefaultRSAKeyAlg
case okp.CurveOctetKeyPair:
return k.Curve()
case []byte:
if sig {
return DefaultHMACSignAlg
}
return DefaultAESKeyAlg
default:
return ""
}
}
// NormalizationSettings contains settings for the normalization preformed by
// KeySpec.Normalize()
type NormalizationSettings struct {
// Use tells KeySpec.Normalize() to set the 'use' field to the specified string
Use string
// RequireKeyID tells KeySpec.Normalize() to attempt to auto-generate 'kid' if it
// is missing and fail if it couldn't generate it automatically.
// Automatic generation is done by creating a SHA-256 thumbprint of the key.
RequireKeyID bool
// RequireAlgorithm requires 'alg' to be specified.
RequireAlgorithm bool
// ThumbprintHashFunc specifies the hash function to use for the thumbprint
ThumbprintHashFunc hash.Hash
}
// Normalize attempts to put some uniformity on the metadata fields attached to the JSON Web Key
// The normalization is influenced by the settings parameter.
func (k *KeySpec) Normalize(settings NormalizationSettings) error {
// Normalize key use
if k.Use == "" {
k.Use = settings.Use
} else if settings.Use != "" {
if k.Use != settings.Use {
return fmt.Errorf("expected key use to be '%s' but got '%s", settings.Use, k.Use)
}
}
// Write algorithm only if empty
if k.Algorithm == "" {
switch k.Use {
case "sig":
k.Algorithm = getKeyAlgo(k.Key, true)
case "enc":
k.Algorithm = getKeyAlgo(k.Key, false)
}
if k.Algorithm == "" && settings.RequireAlgorithm {
// Algorithm could not be guessed, but it is a mandatory field
return errors.New("could not detect algorithm for specified key")
}
}
// Generate unique (hash-based) Key ID only if empty
if k.KeyID == "" {
var err error
var thumbprint []byte
if settings.ThumbprintHashFunc == nil {
thumbprint, err = k.Thumbprint()
} else {
thumbprint, err = k.ThumbprintUsing(settings.ThumbprintHashFunc)
}
if err != nil {
return err
}
if thumbprint != nil {
// We succeeded generating a thumbprint for the key: encode it with Base64URL and use result as Key ID.
k.KeyID = base64.RawURLEncoding.EncodeToString(thumbprint)
} else if settings.RequireKeyID {
// We failed generating a thumbprint for the key, but Key ID is mandatory
return errors.New("key has no key ID specified and key ID generation from thumbprint failed")
}
}
return nil
}