est

package module
v0.0.0-...-5ded594 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 24, 2023 License: MIT Imports: 30 Imported by: 0

README

est

GoDoc Build Status Go Report Card

An implementation of the Enrollment over Secure Transport (EST) certificate enrollment protocol as defined by RFC7030.

The implementation provides:

  • An EST client library;
  • An EST client command line utility using the client library; and
  • An EST server which can be used for testing and development purposes.

The implementation is intended to be mostly feature-complete, including support for:

  • The optional /csrattrs and /serverkeygen operations, with support for server-generated private keys returned with or without additional encryption
  • The optional additional path segment
  • Optional HTTP-based client authentication on top of certificate-based TLS authentication

In addition, a non-standard operation is implemented enabling EST-like enrollment using the privacy preserving protocol for distributing credentials for keys on a Trusted Platform Module (TPM) 2.0 device, as described in Part 1, section 24 of the Trusted Platform Module 2.0 Library specification.

Installation

go install github.com/globalsign/est/cmd/estserver@latest
go install github.com/globalsign/est/cmd/estclient@latest

Quickstart

Starting the server

When started with no configuration file, the EST server listens on localhost:8443 and generates a random, transient Certificate Authority (CA) which can be used for testing:

user@host:$ estserver &
[1] 62405

Refer to the documentation for more details on using a configuration file.

Getting the CA certificates

Because we're using a random, transient CA, we must retrieve the CA certificates in insecure mode to establish an explicit trust anchor for subsequent EST operations. Since we only need the root CA certificate to establish a trust anchor, we use the -rootout flag:

user@host:$ estclient cacerts -server localhost:8443 -insecure -rootout -out anchor.pem

We will also obtain and store the full CA certificates chain, since we'll use it shortly to demonstrate reenrollment. Since we now have an explicit trust anchor, we can use it instead of the -insecure option. Since we're storing the full chain, we don't use the -rootout option here:

user@host:$ estclient cacerts -server localhost:8443 -explicit anchor.pem -out cacerts.pem
Enrolling with an existing private key

First we generate a new private key, here using openssl:

user@host:$ openssl genrsa 4096 > key.pem
Generating RSA private key, 4096 bit long modulus
.................+++
.............+++
e is 65537 (0x10001)

Then we generate a PKCS#10 certificate signing request, and enroll using the explicit trust anchor we previously obtained:

user@host:$ estclient csr -key key.pem -cn 'John Doe' -emails 'john@doe.com' -out csr.pem
user@host:$ estclient enroll -server localhost:8443 -explicit anchor.pem -csr csr.pem -out cert.pem

Using a configuration file, we can enroll with a private key resident on a hardware module, such as a hardware security module (HSM) or a Trusted Platform Module 2.0 (TPM) device. Refer to the documentation for more details.

Enrolling with a server-generated private key

If we're unable or unwilling to create our own private key, the EST server can generate one for us, and return it along with our certificate:

user@host:$ estclient serverkeygen -server localhost:8443 -explicit anchor.pem -cn 'Jane Doe' -out cert.pem -keyout key.pem

Note that we can omit the -csr option when enrolling and the EST client can dynamically generate a CSR for us using fields passed at the command line and the private key we specified, or an automatically-generated ephemeral private key if we are requesting server-side private key generation.

Reenrolling

Whichever way we generated our private key, we can now use it to reenroll.

To reenroll a previously obtained certificate, we must use it to authenticate ourselves during the TLS handshake with the EST server. Since our random, transient CA uses an intermediate CA certificate, we must provide a chain of certificates to the EST client, or the TLS handshake may fail.

Although providing the root CA certificate is optional for a TLS handshake, the simplest option is to provide the certificate we received along with the full chain of CA certificates which we previously obtained. To do this, we can just append those CA certificates to the certificate we received, and use that chain to reenroll:

user@host:$ cat cert.pem cacerts.pem >> certs.pem
user@host:$ estclient reenroll -server localhost:8443 -explicit anchor.pem -key key.pem -certs certs.pem -out newcert.pem

Note that when we omit the -csr option when reenrolling, the EST client automatically generates a CSR for us by copying the subject field and subject alternative name extension from the certificate we're renewing.

Documentation

Overview

Package est provides an EST client and server as defined by RFC7030.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewRouter

func NewRouter(cfg *ServerConfig) (http.Handler, error)

NewRouter creates a new EST server mux.

Types

type Attribute

type Attribute struct {
	Type   asn1.ObjectIdentifier
	Values AttributeValueSET
}

Attribute is a CSR Attribute type, as defined by RFC7030 4.5.2.

type AttributeValueSET

type AttributeValueSET []interface{}

AttributeValueSET is an ASN.1 SET of CSR attribute values.

type CA

type CA interface {
	// CACerts requests a copy of the current CA certificates. See RFC7030 4.1.
	CACerts(ctx context.Context, aps string, r *http.Request) ([]*x509.Certificate, error)

	// CSRAttrs requests a list of CA-desired CSR attributes. The returned list
	// may be empty. See RFC7030 4.5.
	CSRAttrs(ctx context.Context, aps string, r *http.Request) (CSRAttrs, error)

	// Enroll requests a new certificate. See RFC7030 4.2.
	Enroll(ctx context.Context, csr *x509.CertificateRequest, aps string, r *http.Request) (*x509.Certificate, error)

	// Reenroll requests renewal/rekey of an existing certificate. See RFC7030
	// 4.2.
	Reenroll(ctx context.Context, cert *x509.Certificate, csr *x509.CertificateRequest, aps string, r *http.Request) (*x509.Certificate, error)

	// ServerKeyGen requests a new certificate and a private key. The key must
	// be returned as a DER-encoded PKCS8 PrivateKeyInfo structure if additional
	// encryption is not being employed, or returned inside a CMS SignedData
	// structure which itself is inside a CMS EnvelopedData structure. See
	// RFC7030 4.4.
	ServerKeyGen(ctx context.Context, csr *x509.CertificateRequest, aps string, r *http.Request) (*x509.Certificate, []byte, error)

	// TPMEnroll requests a new certificate using the TPM 2.0 privacy-preserving
	// protocol. An EK certificate chain with a length of at least one must be
	// provided, along with the EK and AK public areas. The return values are an
	// encrypted credential blob, an encrypted seed, and the certificate itself
	// inside a CMS EnvelopedData encrypted with the credential as a pre-shared
	// key.
	TPMEnroll(ctx context.Context, csr *x509.CertificateRequest, ekcerts []*x509.Certificate, ekPub, akPub []byte, aps string, r *http.Request) ([]byte, []byte, []byte, error)
}

CA is a Certificate Authority backing an EST server. The server can be connected to any backing CA by providing an implementation of this interface.

All operations receive:

  • a context, from which the EST server logger can be retrieved by calling LoggerFromContext
  • the optional URI additional path segment (RFC7030 3.2.2)
  • the HTTP request object from the server, from which the HTTP headers passed by the client (including the Host header, to support virtual servers) can be obtained

Any error object returned from these functions which implements Error will be used by the EST server to determine the HTTP response code, human-readable error description, and Retry-After header value, if applicable. Any other error will be treated as an internal server error.

type CSRAttrs

type CSRAttrs struct {
	OIDs       []asn1.ObjectIdentifier
	Attributes []Attribute
}

CSRAttrs contains CSR attributes as defined by RFC7030 4.5.

CSR attributes are defined by RFC7030 as a sequence of AttrOrOID, where AttrOrOID is a CHOICE of Object Identifier or Attribute. For ease of use, CRSAttrs provides separately a list of Object Identifiers, and a list of Attributes.

When the EST client retrieves and parses CSR attributes from an EST server, attribute values of the ASN.1 types: - OBJECT IDENTIFIER - BOOLEAN - INTEGER - most STRING types

will be unmarshalled into the Attribute.Values field as standard Go asn1.ObjectIdentifier, bool, *big.Int and string types where possible, and they can be retrieved via a type assertion. Other types will be unmarshalled into an asn1.RawValue structure and must be interpreted by the caller.

func (CSRAttrs) Marshal

func (a CSRAttrs) Marshal() ([]byte, error)

Marshal returns the ASN.1 DER-encoding of a value.

func (*CSRAttrs) Unmarshal

func (a *CSRAttrs) Unmarshal(b []byte) error

Unmarshal parses an DER-encoded ASN.1 data structure and stores the result in the object. Attribute values of the ASN.1 types: - OBJECT IDENTIFIER - BOOLEAN - INTEGER - most STRING types

will be unmarshalled into standard Go asn1.ObjectIdentifier, bool, *big.Int and string types where possible, and can be retrieved via a type assertion. Other types will be unmarshalled into an asn1.RawValue structure and must be interpreted by the caller.

type Client

type Client struct {
	// Host is the host:path of the EST server excluding any URL path
	// component, e.g. est.server.com:8443
	Host string

	// AdditionalPathSegment is an optional label for EST servers to provide
	// service for multiple CAs. See RFC7030 3.2.2.
	AdditionalPathSegment string

	// ExplicitAnchor is the optional Explicit TA database. See RFC7030 3.6.1.
	ExplicitAnchor *x509.CertPool

	// ImplicitAnchor is an optional Implicit TA database. If nil, the system
	// certificate pool will be used. See RFC7030 3.6.2.
	ImplicitAnchor *x509.CertPool

	// Certificates are the client certificates to present to the EST server
	// during the handshake. If more than one certificate is provided, they
	// should be provided in order, with the end-entity certificate first, and
	// the root CA (or last intermediate CA) certificate last.
	Certificates []*x509.Certificate

	// PrivateKey is the private key associated with the end-entity TLS
	// certificate. Any object implementing crypto.Signer may be used, to
	// support private keys resident on a hardware security module (HSM),
	// Trusted Platform Module (TPM) or other hardware device.
	PrivateKey interface{}

	// AdditionalHeaders are additional HTTP headers to include with the
	// request to the EST server.
	AdditionalHeaders map[string]string

	// HostHeader overrides the default Host header for the HTTP request to the
	// EST server, and is mostly useful for testing.
	HostHeader string

	// Username is an optional HTTP Basic Authentication username.
	Username string

	// Password is an optional HTTP Basic Authentication password.
	Password string

	// DisableKeepAlives disables HTTP keep-alives if set.
	DisableKeepAlives bool

	// InsecureSkipVerify controls whether the client verifies the EST server's
	// certificate chain and host name. If true, the client accepts any
	// certificate presented by the server and any host name in that certificate.
	// In this mode, TLS is susceptible to man-in-the-middle attacks. This should
	// be used only for testing. If used to obtain the CA certificates from an
	// otherwise untrusted EST server, those certificates must be manually
	// verified in some out-of-band manner before any further EST operations with
	// that server are performed.
	InsecureSkipVerify bool
}

Client is an EST client implementing the Enrollment over Secure Transport protocol as defined in RFC7030.

All EST client operations will return an error object implementing Error when the EST server returns any status other than 200 OK. The status code, description and, if applicable, retry-after seconds can be extracted from that object. In order to make the retry-after seconds available through this mechanism, note that a 202 Accepted response to enroll and reenroll operations is returned as an error for this purpose, even though 2** status codes indicate success.

func (*Client) CACerts

func (c *Client) CACerts(ctx context.Context) ([]*x509.Certificate, error)

CACerts requests a copy of the current CA certificates.

func (*Client) CSRAttrs

func (c *Client) CSRAttrs(ctx context.Context) (CSRAttrs, error)

CSRAttrs requests a list of CA-desired CSR attributes.

func (*Client) Enroll

Enroll requests a new certificate.

func (*Client) Reenroll

Reenroll renews an existing certificate.

func (*Client) ServerKeyGen

func (c *Client) ServerKeyGen(ctx context.Context, r *x509.CertificateRequest) (*x509.Certificate, []byte, error)

ServerKeyGen requests a new certificate and a server-generated private key.

func (*Client) TPMEnroll

func (c *Client) TPMEnroll(
	ctx context.Context,
	r *x509.CertificateRequest,
	ekCerts []*x509.Certificate,
	ekPub []byte,
	akPub []byte,
) ([]byte, []byte, []byte, error)

TPMEnroll requests a certificate using the TPM 2.0 privacy preserving protocol for distributing credentials for keys on a TPM.

type Error

type Error interface {
	// StatusCode returns the HTTP status code.
	StatusCode() int

	// Error returns a human-readable description of the error.
	Error() string

	// RetryAfter returns the value in seconds after which the client should
	// retry the request.
	RetryAfter() int
}

Error represents an error which can be translated into an HTTP status code and message, and optionally specify a Retry-After period.

type Logger

type Logger interface {
	// Errorf uses fmt.Sprintf to log a formatted message.
	Errorf(format string, args ...interface{})

	// Errorw logs a message with some additional context. The variadic
	// key-value pairs are treated as they are in With.
	Errorw(format string, keysAndValues ...interface{})

	// Infof uses fmt.Sprintf to log a formatted message.
	Infof(format string, args ...interface{})

	// Infow logs a message with some additional context. The variadic
	// key-value pairs are treated as they are in With.
	Infow(format string, keysAndValues ...interface{})

	// With adds a variadic number of key-values pairs to the logging context.
	// The first element of the pair is used as the field key and should be a
	// string. Passing a non-string key or passing an orphaned key panics.
	With(keysAndValues ...interface{}) Logger
}

Logger is an interface for an EST server logger.

func LoggerFromContext

func LoggerFromContext(ctx context.Context) Logger

LoggerFromContext returns a logger included in a context.

type ServerConfig

type ServerConfig struct {
	// CA is an interface to the Certificate Authority backing the EST server.
	CA CA

	// Logger is an optional logger. The logger can be retrieved by the backing
	// CA from the HTTP request context using LoggerFromContext.
	Logger Logger

	// Timeout sets a request timeout. If zero, a reasonable default will be
	// used.
	Timeout time.Duration

	// AllowedHosts is an optional list of fully-qualified domain names
	// representing hosts which are allowed to serve the EST service.
	AllowedHosts []string

	// RateLimit is an optional rate limit expressed in requests per second.
	// If zero, no rate limit will be applied.
	RateLimit int

	// CheckBasicAuth is an optional callback function to check HTTP Basic
	// Authentication credentials. A nil error means that authentication was
	// successful, and a non-nil error means that it was not. If CheckBasicAuth
	// is nil, then HTTP Basic Authentication is not required for any EST
	// operation, but access to the /healthcheck endpoint will be blocked.
	CheckBasicAuth func(ctx context.Context, r *http.Request, aps, username, password string) error
}

ServerConfig contains EST server configuration options.

Directories

Path Synopsis
cmd
estclient
Application estclient is an EST client.
Application estclient is an EST client.
estserver
Application estserver is a basic EST server for testing purposes.
Application estserver is a basic EST server for testing purposes.
internal
basiclogger
Package basiclogger provides a basic logger implementing est.Logger, for demonstration and testing purposes.
Package basiclogger provides a basic logger implementing est.Logger, for demonstration and testing purposes.
mockca
Package mockca provides a mock certificate authority for testing purposes.
Package mockca provides a mock certificate authority for testing purposes.
tpm
Package tpm provides TPM 2.0 credential-related functionality.
Package tpm provides TPM 2.0 credential-related functionality.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL