xref: /aosp_15_r20/external/tink/go/jwt/jwt_ecdsa_signer_key_manager.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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