github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/cloudflare/cfssl/auth/auth.go (about)

     1  // Package auth implements an interface for providing CFSSL
     2  // authentication. This is meant to authenticate a client CFSSL to a
     3  // remote CFSSL in order to prevent unauthorised use of the signature
     4  // capabilities. This package provides both the interface and a
     5  // standard HMAC-based implementation.
     6  package auth
     7  
     8  import (
     9  	"crypto/hmac"
    10  	"crypto/sha256"
    11  	"encoding/hex"
    12  	"fmt"
    13  	"io/ioutil"
    14  	"os"
    15  	"strings"
    16  )
    17  
    18  // An AuthenticatedRequest contains a request and authentication
    19  // token. The Provider may determine whether to validate the timestamp
    20  // and remote address.
    21  type AuthenticatedRequest struct {
    22  	// An Authenticator decides whether to use this field.
    23  	Timestamp     int64  `json:"timestamp,omitempty"`
    24  	RemoteAddress []byte `json:"remote_address,omitempty"`
    25  	Token         []byte `json:"token"`
    26  	Request       []byte `json:"request"`
    27  }
    28  
    29  // A Provider can generate tokens from a request and verify a
    30  // request. The handling of additional authentication data (such as
    31  // the IP address) is handled by the concrete type, as is any
    32  // serialisation and state-keeping.
    33  type Provider interface {
    34  	Token(req []byte) (token []byte, err error)
    35  	Verify(aReq *AuthenticatedRequest) bool
    36  }
    37  
    38  // Standard implements an HMAC-SHA-256 authentication provider. It may
    39  // be supplied additional data at creation time that will be used as
    40  // request || additional-data with the HMAC.
    41  type Standard struct {
    42  	key []byte
    43  	ad  []byte
    44  }
    45  
    46  // New generates a new standard authentication provider from the key
    47  // and additional data. The additional data will be used when
    48  // generating a new token.
    49  func New(key string, ad []byte) (*Standard, error) {
    50  	if splitKey := strings.SplitN(key, ":", 2); len(splitKey) == 2 {
    51  		switch splitKey[0] {
    52  		case "env":
    53  			key = os.Getenv(splitKey[1])
    54  		case "file":
    55  			data, err := ioutil.ReadFile(splitKey[1])
    56  			if err != nil {
    57  				return nil, err
    58  			}
    59  			key = string(data)
    60  		default:
    61  			return nil, fmt.Errorf("unknown key prefix: %s", splitKey[0])
    62  		}
    63  	}
    64  
    65  	keyBytes, err := hex.DecodeString(key)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  
    70  	return &Standard{keyBytes, ad}, nil
    71  }
    72  
    73  // Token generates a new authentication token from the request.
    74  func (p Standard) Token(req []byte) (token []byte, err error) {
    75  	h := hmac.New(sha256.New, p.key)
    76  	h.Write(req)
    77  	h.Write(p.ad)
    78  	return h.Sum(nil), nil
    79  }
    80  
    81  // Verify determines whether an authenticated request is valid.
    82  func (p Standard) Verify(ad *AuthenticatedRequest) bool {
    83  	if ad == nil {
    84  		return false
    85  	}
    86  
    87  	// Standard token generation returns no error.
    88  	token, _ := p.Token(ad.Request)
    89  	if len(ad.Token) != len(token) {
    90  		return false
    91  	}
    92  
    93  	return hmac.Equal(token, ad.Token)
    94  }