1// Copyright 2018 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 signature 18 19import ( 20 "fmt" 21 22 "github.com/google/tink/go/core/primitiveset" 23 "github.com/google/tink/go/internal/internalregistry" 24 "github.com/google/tink/go/internal/monitoringutil" 25 "github.com/google/tink/go/keyset" 26 "github.com/google/tink/go/monitoring" 27 "github.com/google/tink/go/tink" 28 tinkpb "github.com/google/tink/go/proto/tink_go_proto" 29) 30 31// NewSigner returns a Signer primitive from the given keyset handle. 32func NewSigner(handle *keyset.Handle) (tink.Signer, error) { 33 ps, err := handle.Primitives() 34 if err != nil { 35 return nil, fmt.Errorf("public_key_sign_factory: cannot obtain primitive set: %s", err) 36 } 37 return newWrappedSigner(ps) 38} 39 40// wrappedSigner is an Signer implementation that uses the underlying primitive set for signing. 41type wrappedSigner struct { 42 ps *primitiveset.PrimitiveSet 43 logger monitoring.Logger 44} 45 46// Asserts that wrappedSigner implements the Signer interface. 47var _ tink.Signer = (*wrappedSigner)(nil) 48 49func newWrappedSigner(ps *primitiveset.PrimitiveSet) (*wrappedSigner, error) { 50 if _, ok := (ps.Primary.Primitive).(tink.Signer); !ok { 51 return nil, fmt.Errorf("public_key_sign_factory: not a Signer primitive") 52 } 53 54 for _, primitives := range ps.Entries { 55 for _, p := range primitives { 56 if _, ok := (p.Primitive).(tink.Signer); !ok { 57 return nil, fmt.Errorf("public_key_sign_factory: not an Signer primitive") 58 } 59 } 60 } 61 logger, err := createSignerLogger(ps) 62 if err != nil { 63 return nil, err 64 } 65 return &wrappedSigner{ 66 ps: ps, 67 logger: logger, 68 }, nil 69} 70 71func createSignerLogger(ps *primitiveset.PrimitiveSet) (monitoring.Logger, error) { 72 // only keysets which contain annotations are monitored. 73 if len(ps.Annotations) == 0 { 74 return &monitoringutil.DoNothingLogger{}, nil 75 } 76 keysetInfo, err := monitoringutil.KeysetInfoFromPrimitiveSet(ps) 77 if err != nil { 78 return nil, err 79 } 80 return internalregistry.GetMonitoringClient().NewLogger(&monitoring.Context{ 81 KeysetInfo: keysetInfo, 82 Primitive: "public_key_sign", 83 APIFunction: "sign", 84 }) 85} 86 87// Sign signs the given data and returns the signature concatenated with the identifier of the 88// primary primitive. 89func (s *wrappedSigner) Sign(data []byte) ([]byte, error) { 90 primary := s.ps.Primary 91 signer, ok := (primary.Primitive).(tink.Signer) 92 if !ok { 93 return nil, fmt.Errorf("public_key_sign_factory: not a Signer primitive") 94 } 95 96 var signedData []byte 97 if primary.PrefixType == tinkpb.OutputPrefixType_LEGACY { 98 signedData = make([]byte, 0, len(data)+1) 99 signedData = append(signedData, data...) 100 signedData = append(signedData, byte(0)) 101 } else { 102 signedData = data 103 } 104 105 signature, err := signer.Sign(signedData) 106 if err != nil { 107 s.logger.LogFailure() 108 return nil, err 109 } 110 s.logger.Log(primary.KeyID, len(data)) 111 if len(primary.Prefix) == 0 { 112 return signature, nil 113 } 114 output := make([]byte, 0, len(primary.Prefix)+len(signature)) 115 output = append(output, primary.Prefix...) 116 output = append(output, signature...) 117 return output, nil 118} 119