auth.go 2.6 KB

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