1// Copyright 2022 Google LLC 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//////////////////////////////////////////////////////////////////////////////// 16 17package jwt 18 19import ( 20 "fmt" 21 22 "google.golang.org/protobuf/proto" 23 "github.com/google/tink/go/core/registry" 24 "github.com/google/tink/go/keyset" 25 macsubtle "github.com/google/tink/go/mac/subtle" 26 "github.com/google/tink/go/subtle/random" 27 "github.com/google/tink/go/subtle" 28 jwtmacpb "github.com/google/tink/go/proto/jwt_hmac_go_proto" 29 tinkpb "github.com/google/tink/go/proto/tink_go_proto" 30) 31 32const ( 33 jwtHMACKeyVersion = 0 34 jwtHMACTypeURL = "type.googleapis.com/google.crypto.tink.JwtHmacKey" 35) 36 37// jwtHMACKeyManager is an implementation of the KeyManager interface 38type jwtHMACKeyManager struct{} 39 40// Assert that jwtHMACKeyManager implements the KeyManager interface. 41var _ registry.KeyManager = (*jwtHMACKeyManager)(nil) 42 43var hsAlgToHash = map[jwtmacpb.JwtHmacAlgorithm]string{ 44 jwtmacpb.JwtHmacAlgorithm_HS256: "SHA256", 45 jwtmacpb.JwtHmacAlgorithm_HS384: "SHA384", 46 jwtmacpb.JwtHmacAlgorithm_HS512: "SHA512", 47} 48 49var hsAlgToMinKeySizeBytes = map[jwtmacpb.JwtHmacAlgorithm]int{ 50 jwtmacpb.JwtHmacAlgorithm_HS256: 32, 51 jwtmacpb.JwtHmacAlgorithm_HS384: 48, 52 jwtmacpb.JwtHmacAlgorithm_HS512: 64, 53} 54 55func (km *jwtHMACKeyManager) Primitive(serializedKey []byte) (interface{}, error) { 56 key := &jwtmacpb.JwtHmacKey{} 57 if err := proto.Unmarshal(serializedKey, key); err != nil { 58 return nil, err 59 } 60 if err := km.validateKey(key); err != nil { 61 return nil, err 62 } 63 hashAlg, ok := hsAlgToHash[key.GetAlgorithm()] 64 if !ok { 65 return nil, fmt.Errorf("invalid algorithm: '%v'", key.GetAlgorithm()) 66 } 67 tagSize, err := subtle.GetHashDigestSize(hashAlg) 68 if err != nil { 69 return nil, err 70 } 71 mac, err := macsubtle.NewHMAC(hashAlg, key.GetKeyValue(), tagSize) 72 if err != nil { 73 return nil, err 74 } 75 var kid *string = nil 76 if key.GetCustomKid() != nil { 77 k := key.GetCustomKid().GetValue() 78 kid = &k 79 } 80 return newMACWithKID(mac, key.GetAlgorithm().String(), kid) 81} 82 83func (km *jwtHMACKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { 84 if serializedKeyFormat == nil || len(serializedKeyFormat) == 0 { 85 return nil, fmt.Errorf("no serialized key format") 86 } 87 keyFormat := &jwtmacpb.JwtHmacKeyFormat{} 88 if err := proto.Unmarshal(serializedKeyFormat, keyFormat); err != nil { 89 return nil, err 90 } 91 if err := km.validateKeyFormat(keyFormat); err != nil { 92 return nil, err 93 } 94 return &jwtmacpb.JwtHmacKey{ 95 Version: jwtHMACKeyVersion, 96 Algorithm: keyFormat.GetAlgorithm(), 97 KeyValue: random.GetRandomBytes(keyFormat.KeySize), 98 }, nil 99} 100 101func (km *jwtHMACKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { 102 key, err := km.NewKey(serializedKeyFormat) 103 if err != nil { 104 return nil, err 105 } 106 serializedKey, err := proto.Marshal(key) 107 if err != nil { 108 return nil, err 109 } 110 return &tinkpb.KeyData{ 111 TypeUrl: jwtHMACTypeURL, 112 Value: serializedKey, 113 KeyMaterialType: tinkpb.KeyData_SYMMETRIC, 114 }, nil 115} 116 117// DoesSupport indicates if this key manager supports the given key type. 118func (km *jwtHMACKeyManager) DoesSupport(keyTypeURL string) bool { 119 return jwtHMACTypeURL == keyTypeURL 120} 121 122// TypeURL returns the key type of keys managed by this key manager. 123func (km *jwtHMACKeyManager) TypeURL() string { 124 return jwtHMACTypeURL 125} 126 127func (km *jwtHMACKeyManager) validateKey(key *jwtmacpb.JwtHmacKey) error { 128 if key == nil { 129 return fmt.Errorf("key can't be nil") 130 } 131 if err := keyset.ValidateKeyVersion(key.Version, jwtHMACKeyVersion); err != nil { 132 return err 133 } 134 minKeySizeBytes, ok := hsAlgToMinKeySizeBytes[key.GetAlgorithm()] 135 if !ok { 136 return fmt.Errorf("invalid algorithm: '%v'", key.GetAlgorithm()) 137 } 138 if len(key.KeyValue) < minKeySizeBytes { 139 return fmt.Errorf("invalid JwtHmacKey: KeyValue is too short") 140 } 141 return nil 142} 143 144func (km *jwtHMACKeyManager) validateKeyFormat(keyFormat *jwtmacpb.JwtHmacKeyFormat) error { 145 if keyFormat == nil { 146 return fmt.Errorf("key format can't be nil") 147 } 148 minKeySizeBytes, ok := hsAlgToMinKeySizeBytes[keyFormat.GetAlgorithm()] 149 if !ok { 150 return fmt.Errorf("invalid algorithm: '%v'", keyFormat.GetAlgorithm()) 151 } 152 if int(keyFormat.KeySize) < minKeySizeBytes { 153 return fmt.Errorf("invalid JwtHmacKeyFormat: KeySize is too small") 154 } 155 return nil 156} 157