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 "crypto/ecdsa" 21 "crypto/rand" 22 "errors" 23 "fmt" 24 25 "google.golang.org/protobuf/proto" 26 "github.com/google/tink/go/core/registry" 27 "github.com/google/tink/go/keyset" 28 subtlesign "github.com/google/tink/go/signature/subtle" 29 "github.com/google/tink/go/subtle" 30 jepb "github.com/google/tink/go/proto/jwt_ecdsa_go_proto" 31 tinkpb "github.com/google/tink/go/proto/tink_go_proto" 32) 33 34const ( 35 jwtECDSASignerKeyVersion = 0 36 jwtECDSASignerTypeURL = "type.googleapis.com/google.crypto.tink.JwtEcdsaPrivateKey" 37) 38 39var ( 40 errECDSAInvalidKey = errors.New("invalid JwtEcdsaPrivateKey key") 41 errECDSAInvalidKeyFormat = errors.New("invalid key format") 42) 43 44// jwtECDSASignerKeyManager implements the KeyManager interface 45// for JWT Signing using the 'ES256', 'ES384', and 'ES512' JWA algorithm. 46type jwtECDSASignerKeyManager struct{} 47 48var _ registry.PrivateKeyManager = (*jwtECDSASignerKeyManager)(nil) 49 50func (km *jwtECDSASignerKeyManager) Primitive(serializedKey []byte) (interface{}, error) { 51 if serializedKey == nil { 52 return nil, errECDSAInvalidKey 53 } 54 privKey := &jepb.JwtEcdsaPrivateKey{} 55 if err := proto.Unmarshal(serializedKey, privKey); err != nil { 56 return nil, fmt.Errorf("failed to unmarshal JwtEcdsaPrivateKey: %v", err) 57 } 58 params, err := km.validateKey(privKey) 59 if err != nil { 60 return nil, err 61 } 62 ts, err := subtlesign.NewECDSASigner(params.Hash, params.Curve, jwtECDSAEncoding, privKey.GetKeyValue()) 63 if err != nil { 64 return nil, fmt.Errorf("failed to create ECDSASigner: %v", err) 65 } 66 pubKey := privKey.GetPublicKey() 67 var kid *string = nil 68 if pubKey.GetCustomKid() != nil { 69 k := pubKey.GetCustomKid().GetValue() 70 kid = &k 71 } 72 return newSignerWithKID(ts, pubKey.GetAlgorithm().String(), kid) 73} 74 75func (km *jwtECDSASignerKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { 76 if serializedKeyFormat == nil { 77 return nil, errECDSAInvalidKeyFormat 78 } 79 keyFormat := &jepb.JwtEcdsaKeyFormat{} 80 if err := proto.Unmarshal(serializedKeyFormat, keyFormat); err != nil { 81 return nil, fmt.Errorf("failed to unmarshal JwtEcdsaKeyFormat: %v", err) 82 } 83 params, ok := esAlgToParams[keyFormat.GetAlgorithm()] 84 if !ok { 85 return nil, errECDSAInvalidAlgorithm 86 } 87 k, err := ecdsa.GenerateKey(subtle.GetCurve(params.Curve), rand.Reader) 88 if err != nil { 89 return nil, fmt.Errorf("failed to generate key: %v", err) 90 } 91 return &jepb.JwtEcdsaPrivateKey{ 92 Version: jwtECDSASignerKeyVersion, 93 PublicKey: &jepb.JwtEcdsaPublicKey{ 94 Version: jwtECDSASignerKeyVersion, 95 Algorithm: keyFormat.GetAlgorithm(), 96 X: k.X.Bytes(), 97 Y: k.Y.Bytes(), 98 }, 99 KeyValue: k.D.Bytes(), 100 }, nil 101} 102 103func (km *jwtECDSASignerKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { 104 if serializedKeyFormat == nil { 105 return nil, errECDSAInvalidKeyFormat 106 } 107 key, err := km.NewKey(serializedKeyFormat) 108 if err != nil { 109 return nil, err 110 } 111 serializedKey, err := proto.Marshal(key) 112 if err != nil { 113 return nil, fmt.Errorf("failed to marshal JwtEcdsaPrivateKey: %v", err) 114 } 115 return &tinkpb.KeyData{ 116 TypeUrl: jwtECDSASignerTypeURL, 117 Value: serializedKey, 118 KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PRIVATE, 119 }, nil 120} 121 122func (km *jwtECDSASignerKeyManager) PublicKeyData(serializedPrivKey []byte) (*tinkpb.KeyData, error) { 123 if serializedPrivKey == nil { 124 return nil, errECDSAInvalidKey 125 } 126 privKey := &jepb.JwtEcdsaPrivateKey{} 127 if err := proto.Unmarshal(serializedPrivKey, privKey); err != nil { 128 return nil, fmt.Errorf("failed to unmarshal JwtEcdsaPrivateKey: %v", err) 129 } 130 serializedPubKey, err := proto.Marshal(privKey.GetPublicKey()) 131 if err != nil { 132 return nil, err 133 } 134 return &tinkpb.KeyData{ 135 TypeUrl: jwtECDSAVerifierTypeURL, 136 Value: serializedPubKey, 137 KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PUBLIC, 138 }, nil 139} 140 141func (km *jwtECDSASignerKeyManager) DoesSupport(typeURL string) bool { 142 return jwtECDSASignerTypeURL == typeURL 143} 144 145func (km *jwtECDSASignerKeyManager) TypeURL() string { 146 return jwtECDSASignerTypeURL 147} 148 149func (km *jwtECDSASignerKeyManager) validateKey(key *jepb.JwtEcdsaPrivateKey) (ecdsaParams, error) { 150 if err := keyset.ValidateKeyVersion(key.Version, jwtECDSASignerKeyVersion); err != nil { 151 return ecdsaParams{}, fmt.Errorf("invalid key version: %v", err) 152 } 153 if key.GetPublicKey() == nil { 154 return ecdsaParams{}, fmt.Errorf("no public key in JwtEcdsaPrivateKey") 155 } 156 params, ok := esAlgToParams[key.GetPublicKey().GetAlgorithm()] 157 if !ok { 158 return ecdsaParams{}, errECDSAInvalidAlgorithm 159 } 160 return params, nil 161} 162