@@ -51,6 +51,9 @@ type Server struct {
51
51
listeners map [net.Listener ]map [net.Conn ]struct {}
52
52
shutdown bool
53
53
mtx sync.Mutex
54
+
55
+ signTimeout time.Duration
56
+ signRetryCount int
54
57
}
55
58
56
59
// NewServer prepares a TLS server capable of receiving connections from keyless clients.
@@ -73,6 +76,8 @@ func NewServer(config *ServeConfig, cert tls.Certificate, keylessCA *x509.CertPo
73
76
dispatcher : rpc .NewServer (),
74
77
limitedDispatcher : rpc .NewServer (),
75
78
listeners : make (map [net.Listener ]map [net.Conn ]struct {}),
79
+ signTimeout : config .signTimeout ,
80
+ signRetryCount : config .signRetryCount ,
76
81
}
77
82
78
83
return s , nil
@@ -448,19 +453,56 @@ func (s *Server) unlimitedDo(pkt *protocol.Packet, connName string) response {
448
453
return makeErrResponse (pkt , protocol .ErrKeyNotFound )
449
454
}
450
455
451
- signSpan , _ := opentracing .StartSpanFromContext (ctx , "execute.Sign" )
456
+ signSpan , ctx := opentracing .StartSpanFromContext (ctx , "execute.Sign" )
452
457
defer signSpan .Finish ()
453
458
var sig []byte
454
- sig , err = key .Sign (rand .Reader , pkt .Operation .Payload , opts )
455
- if err != nil {
456
- tracing .LogError (span , err )
457
- log .Errorf ("Connection %v: %s: Signing error: %v\n " , connName , protocol .ErrCrypto , err )
458
- return makeErrResponse (pkt , protocol .ErrCrypto )
459
+ // By default, we only try the request once, unless retry count is configured
460
+ for attempts := 1 + s .signRetryCount ; attempts > 0 ; attempts -- {
461
+ var err error
462
+ // If signTimeout is not set, the value will be zero
463
+ if s .signTimeout == 0 {
464
+ sig , err = key .Sign (rand .Reader , pkt .Operation .Payload , opts )
465
+ } else {
466
+ ch := make (chan signWithTimeoutWrapper , 1 )
467
+ ctxTimeout , cancel := context .WithTimeout (ctx , s .signTimeout )
468
+ defer cancel ()
469
+
470
+ go signWithTimeout (ctxTimeout , ch , key , rand .Reader , pkt .Operation .Payload , opts )
471
+ select {
472
+ case <- ctxTimeout .Done ():
473
+ sig = nil
474
+ err = ctxTimeout .Err ()
475
+ case result := <- ch :
476
+ sig = result .sig
477
+ err = result .error
478
+ }
479
+ }
480
+ if err != nil {
481
+ if attempts > 1 {
482
+ log .Debugf ("Connection %v: failed sign attempt: %s, %d attempt(s) left" , connName , err , attempts - 1 )
483
+ continue
484
+ } else {
485
+ tracing .LogError (span , err )
486
+ log .Errorf ("Connection %v: %s: Signing error: %v\n " , connName , protocol .ErrCrypto , err )
487
+ return makeErrResponse (pkt , protocol .ErrCrypto )
488
+ }
489
+ }
490
+ break
459
491
}
460
492
461
493
return makeRespondResponse (pkt , sig )
462
494
}
463
495
496
+ type signWithTimeoutWrapper struct {
497
+ sig []byte
498
+ error error
499
+ }
500
+
501
+ func signWithTimeout (ctx context.Context , ch chan signWithTimeoutWrapper , key crypto.Signer , rand io.Reader , digest []byte , opts crypto.SignerOpts ) {
502
+ sig , err := key .Sign (rand , digest , opts )
503
+ ch <- signWithTimeoutWrapper {sig , err }
504
+ }
505
+
464
506
func (s * Server ) limitedDo (pkt * protocol.Packet , connName string ) response {
465
507
spanCtx , err := tracing .SpanContextFromBinary (pkt .Operation .JaegerSpan )
466
508
if err != nil {
@@ -697,6 +739,8 @@ type ServeConfig struct {
697
739
tcpTimeout , unixTimeout time.Duration
698
740
isLimited func (state tls.ConnectionState ) (bool , error )
699
741
customOpFunc CustomOpFunction
742
+ signTimeout time.Duration
743
+ signRetryCount int
700
744
}
701
745
702
746
const (
@@ -718,6 +762,8 @@ func DefaultServeConfig() *ServeConfig {
718
762
unixTimeout : defaultUnixTimeout ,
719
763
maxConnPendingRequests : 1024 ,
720
764
isLimited : func (state tls.ConnectionState ) (bool , error ) { return false , nil },
765
+ signTimeout : 0 ,
766
+ signRetryCount : 0 ,
721
767
}
722
768
}
723
769
@@ -757,6 +803,29 @@ func (s *ServeConfig) WithIsLimited(f func(state tls.ConnectionState) (bool, err
757
803
return s
758
804
}
759
805
806
+ // WithSignTimeout specifies the sign operation timeout. This timeout is used to enforce a
807
+ // max execution time for a single sign operation
808
+ func (s * ServeConfig ) WithSignTimeout (timeout time.Duration ) * ServeConfig {
809
+ s .signTimeout = timeout
810
+ return s
811
+ }
812
+
813
+ // SignTimeout returns the sign operation timeout
814
+ func (s * ServeConfig ) SignTimeout () time.Duration {
815
+ return s .signTimeout
816
+ }
817
+
818
+ // WithSignRetryCount specifics a number of retries to allow for failed sign operations
819
+ func (s * ServeConfig ) WithSignRetryCount (signRetryCount int ) * ServeConfig {
820
+ s .signRetryCount = signRetryCount
821
+ return s
822
+ }
823
+
824
+ // SignRetryCount returns the count of retries allowed for sign operations
825
+ func (s * ServeConfig ) SignRetryCount () int {
826
+ return s .signRetryCount
827
+ }
828
+
760
829
// CustomOpFunction is the signature for custom opcode functions.
761
830
//
762
831
// If it returns a non-nil error which implements protocol.Error, the server
0 commit comments