acme

package
v0.0.6-alpha.1 Latest Latest
Warning

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

Go to latest
Published: Dec 3, 2024 License: Apache-2.0 Imports: 39 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ErrTypeAccountDoesNotExist     = "accountDoesNotExist"
	ErrTypeAlreadyRevoked          = "alreadyRevoked"
	ErrTypeBadCSR                  = "badCSR"
	ErrTypeBadNonce                = "badNonce"
	ErrTypeBadPublicKey            = "badPublicKey"
	ErrTypeBadRevocationReason     = "badRevocationReason"
	ErrTypeBadSignatureAlgorithm   = "badSignatureAlgorithm"
	ErrTypeCAAError                = "caa"
	ErrTypeCompoundError           = "compound"
	ErrTypeConnectionError         = "connection"
	ErrTypeDNSError                = "dns"
	ErrTypeExternalAccountRequired = "externalAccountRequired"
	ErrTypeIncorrectResponse       = "incorrectResponse"
	ErrTypeInvalidContact          = "invalidContact"
	ErrTypeMalformedError          = "malformed"
	ErrTypeOrderNotReady           = "orderNotReady"
	ErrTypeRateLimited             = "rateLimited"
	ErrTypeRejectedIdentifier      = "rejectedIdentifier"
	ErrTypeServerInternal          = "serverInternal"
	ErrTypeTLSError                = "tls"
	ErrTypeUnauthorized            = "unauthorized"
	ErrTypeUnsupportedContact      = "unsupportedContact"
	ErrTypeUnsupportedIdentifier   = "unsupportedIdentifier"
	ErrTypeUserActionRequired      = "userActionRequired"
	ErrTypeAccountExists           = "accountExists"
)

Error definitions as per RFC 8555

View Source
const (
	StatusValid       = "valid"       // Entity is valid (account, order, authorization, certificate)
	StatusPending     = "pending"     // Entity is pending (order, authorization, challenge)
	StatusProcessing  = "processing"  // Entity is processing (order, challenge)
	StatusInvalid     = "invalid"     // Entity is invalid (order, authorization, challenge)
	StatusDeactivated = "deactivated" // Entity is deactivated (account, authorization)
	StatusExpired     = "expired"     // Entity is expired (authorization, certificate)
	StatusRevoked     = "revoked"     // Entity is revoked (account, certificate)
	StatusReady       = "ready"       // Entity is ready (order)

	AuthzTypeDNS                 AuthzType = "dns"
	AuthzTypeIP                  AuthzType = "ip"
	AuthzTypePermanentIdentifier AuthzType = "permanent-identifier"

	ChallengeTypeEnroll01       ChallengeType = "enroll-01"
	ChallengeTypeDNS01          ChallengeType = "dns-01"
	ChallengeTypeHTTP01         ChallengeType = "http-01"
	ChallengeTypeEndorse01      ChallengeType = "endorse-01"
	ChallengeTypeDeviceAttest01 ChallengeType = "device-attest-01"

	// WARNING: magic ahead!
	// Challenge types that support dynamic port configuration, where
	// the port number is derived from the challenge type. Ex: "http-8080"
	// would serve the http-01 challenge type on port 8080, while "http-8081"
	// would serve the http-01 challenge type on port 8081. Likewise,
	// device-8080 would use port 8080 to serve the device-01 challenge
	// while device-8081 would use port 8081. If the challenge type is "-01"
	// type, the port number will default to port 80 instead of port 1.
	DynamicChallengeTypeHTTPX   ChallengeType = "http"
	DynamicChallengeTypeEnrollX ChallengeType = "enroll"
)

ACME status values of Account, Order, Authorization and Challenge objects. See https://tools.ietf.org/html/rfc8555#section-7.1.6 for details.

Variables

View Source
var (
	ErrAccountNotFound           = errors.New("ACME account not found")
	ErrRegistrationFailed        = errors.New("ACME registration failed")
	ErrOrderCreationFailed       = errors.New("ACME order creation failed")
	ErrChallengeResolution       = errors.New("ACME challenge resolution failed")
	ErrChallengeFinalization     = errors.New("ACME challenge finalization failed")
	ErrAuthorizationFailed       = errors.New("ACME authorization failed")
	ErrCABundleDownloadFailed    = errors.New("ACME server certificate bundle download failed")
	ErrInvalidCACertificate      = errors.New("invalid CA certificate")
	ErrInvalidCrossSignerAuthzID = errors.New("invalid cross-signer authorization type, only 'dns' supported")
)
View Source
var (
	ErrInvalidAuthzType            = errors.New("acme: invalid authorization type")
	ErrInvalidChallengeType        = errors.New("acme: invalid challenge type")
	ErrAccountAlreadyExists        = errors.New("acme: account already exists")
	ErrInvalidPortNumber           = errors.New("acme: invalid port number")
	ErrInvalidCertRequest          = errors.New("acme: invalid certificate request")
	ErrChallengeNotFound           = errors.New("acme: challenge not found")
	ErrMissingEnrollmentConfig     = errors.New("acme: missing enrollment configuration")
	ErrCrossSignerSameDirectoryURL = errors.New("acme: cross-signer directory URL must be different from primary directory URL")

	AuthzMap = map[string]AuthzType{
		AuthzTypeDNS.String():                 AuthzTypeDNS,
		AuthzTypeIP.String():                  AuthzTypeIP,
		AuthzTypePermanentIdentifier.String(): AuthzTypePermanentIdentifier,
	}

	ChallengeMap = map[string]ChallengeVerifierFunc{
		ChallengeTypeDeviceAttest01.String(): deviceattest01.Verify,
		ChallengeTypeDNS01.String():          dns01.Verify,
		ChallengeTypeEndorse01.String():      endorse01.Verify,
		ChallengeTypeEnroll01.String():       enroll01.Verify,
		ChallengeTypeHTTP01.String():         http01.Verify,
	}

	DynamicChallengeMap = map[string]ChallengeVerifierFunc{
		DynamicChallengeTypeHTTPX.String():   http01.Verify,
		DynamicChallengeTypeEnrollX.String(): enroll01.Verify,
	}

	AuthzDNSChallengeMap = map[string]bool{
		ChallengeTypeHTTP01.String(): true,
		ChallengeTypeDNS01.String():  true,
	}

	AuthzPermanentIdChallengeMap = map[string]bool{
		ChallengeTypeEndorse01.String():      true,
		ChallengeTypeDeviceAttest01.String(): true,
	}
)

Functions

func AccountDoesNotExist

func AccountDoesNotExist(detail string) *entities.Error

func AccountExistsError

func AccountExistsError(detail, location string) *entities.Error

func AlreadyRevoked

func AlreadyRevoked(detail string) *entities.Error

func BadAttestationStatement

func BadAttestationStatement(detail string) *entities.Error

func BadCSR

func BadCSR(detail string) *entities.Error

func BadNonce

func BadNonce(detail string) *entities.Error

func BadPublicKey

func BadPublicKey(detail string) *entities.Error

func BadRevocationReason

func BadRevocationReason(detail string) *entities.Error

func BadSignatureAlgorithm

func BadSignatureAlgorithm(detail string) *entities.Error

func CAAError

func CAAError(detail string) *entities.Error

func CompoundError

func CompoundError(detail string, subproblems []entities.SubProblem) *entities.Error

func ConnectionError

func ConnectionError(detail string) *entities.Error

func DNSError

func DNSError(detail string) *entities.Error

func ExternalAccountRequired

func ExternalAccountRequired(detail string) *entities.Error

func GenerateAccountID

func GenerateAccountID(pubKey crypto.PublicKey) uint64

func GenerateNonce

func GenerateNonce(length int) (string, error)

GenerateNonce creates a new secure random nonce encoded in URL-safe Base64 without padding

func GenerateOrderID

func GenerateOrderID(authzID acme.AuthzID) uint64

func IncorrectResponse

func IncorrectResponse(detail string) *entities.Error

func InvalidContact

func InvalidContact(detail string) *entities.Error

func IsEnrollXChallenge

func IsEnrollXChallenge(challengeType string) bool

func IsHTTPxChallenge

func IsHTTPxChallenge(challengeType string) bool

func MalformedError

func MalformedError(detail string, subproblems []entities.SubProblem) *entities.Error

func NewDatastore

func NewDatastore(logger *logging.Logger, config *datastore.Config) (dao.Factory, error)

Returns an ACME datastore using the backend specified in the datastore section of the platform configuration file

func OrderNotReady

func OrderNotReady(detail string) *entities.Error

func ParseAuthzIDFromChallengeType

func ParseAuthzIDFromChallengeType(challengeType string) (acme.AuthzID, error)

func ParseChallengeAsDynamicPortAssignment

func ParseChallengeAsDynamicPortAssignment(challengeType string) (string, string, error)

Parse the port number from the challenge type. Ex: "http-8080" would use port 8080 while "http-8081" would use port 8081. If the challenge type is "http-01", use port 80 (per RFC 8555)

func ParseConfiguredChallengeVerifiers

func ParseConfiguredChallengeVerifiers(challenges []string) (map[string]ChallengeVerifierFunc, error)

Parses the list of ACME challenges defined in the platform configuration file

func RateLimited

func RateLimited(detail string) *entities.Error

func RejectedIdentifier

func RejectedIdentifier(detail string) *entities.Error

func ServerInternal

func ServerInternal(detail string) *entities.Error

func TLSError

func TLSError(detail string) *entities.Error

func Unauthorized

func Unauthorized(detail string) *entities.Error

func UnsupportedContact

func UnsupportedContact(detail string) *entities.Error

func UnsupportedIdentifier

func UnsupportedIdentifier(detail string) *entities.Error

func UserActionRequired

func UserActionRequired(detail, instance string) *entities.Error

Types

type AccountConfig

type AccountConfig struct {
	Email    string              `yaml:"email" json:"email" mapstructure:"email"`
	Key      *keystore.KeyConfig `yaml:"key" json:"key" mapstructure:"key"`
	KeyID    string              `yaml:"kid" json:"kid" mapstructure:"kid"`
	Register bool                `yaml:"register" json:"register" mapstructure:"register"`
}

type AuthzID

type AuthzID struct {
	Type  *string `yaml:"type" json:"type" mapstructure:"type"`
	Value *string `yaml:"value" json:"value" mapstructure:"value"`
}

type AuthzType

type AuthzType string

func ParseAuthzType

func ParseAuthzType(authzType string) (AuthzType, error)

func ParseAuthzTypeFromChallengeType

func ParseAuthzTypeFromChallengeType(challengeType string) (AuthzType, error)

func (AuthzType) String

func (authType AuthzType) String() string

type CertificateRequest

type CertificateRequest struct {
	// CA common fields
	PermanentID   string                      `yaml:"permanent-id" json:"permanent_id" mapstructure:"permanent-id"`
	ProdModel     string                      `yaml:"prod-model" json:"prod_model" mapstructure:"prod-model"`
	ProdSerial    string                      `yaml:"prod-serial" json:"prod_serial" mapstructure:"prod-serial"`
	SANS          *ca.SubjectAlternativeNames `yaml:"sans" json:"sans" mapstructure:"sans"`
	Subject       ca.Subject                  `yaml:"subject" json:"subject" mapstructure:"subject"`
	Valid         int                         `yaml:"valid" json:"valid" mapstructure:"valid"`
	KeyAttributes *keystore.KeyAttributes     `yaml:"-" json:"-" mapstructure:"-"`
	// ACME specific fields
	AuthzID       *AuthzID   `yaml:"authz" json:"authz" mapstructure:"authz"`
	ChallengeType string     `yaml:"challenge" json:"challenge" mapstructure:"challenge"`
	CrossSigner   *CrossSign `yaml:"cross-sign" json:"cross_sign" mapstructure:"cross-sign"`
	Renew         int        `yaml:"renew" json:"renew" mapstructure:"renew"`
}

type ChallengeType

type ChallengeType string

func ParseChallengeType

func ParseChallengeType(challengeType string) (ChallengeType, error)

func (ChallengeType) String

func (challengeType ChallengeType) String() string

type ChallengeVerifierFunc

type ChallengeVerifierFunc func(
	resolver *net.Resolver,
	ca ca.CertificateAuthority,
	authzValue, challengePort, challengeToken, expectedKeyAuth string) error

type Client

type Client struct {
	// contains filtered or unexported fields
}

func NewClient

func NewClient(
	config ClientConfig,
	ca ca.CertificateAuthority,
	datastore dao.Factory,
	dnsService *dns.Service,
	webServiceHTTPPort int,
	logger *logging.Logger,
	platformKS tpm2ks.PlatformKeyStorer,
	tpm tpm2.TrustedPlatformModule) (*Client, error)

Creates a new ACME client

func NewCrossSigner

func NewCrossSigner(
	config ClientConfig,
	ca ca.CertificateAuthority,
	datastore dao.Factory,
	dnsService *dns.Service,
	webServiceHTTPPort int,
	logger *logging.Logger,
	platformKS tpm2ks.PlatformKeyStorer,
	tpm tpm2.TrustedPlatformModule) (*Client, error)

func (*Client) Account

func (ac *Client) Account() (*acme.Account, error)

Returns the ACME account associated with the account email provided by the platform configuration file

func (*Client) AccountFromEmail

func (ac *Client) AccountFromEmail(email string) (*acme.Account, error)

Returns the ACME account associated with the provided email address

func (*Client) AccountID

func (ac *Client) AccountID() uint64

Returns the ACME account ID

func (*Client) AccountKeyAttributes

func (ac *Client) AccountKeyAttributes() *keystore.KeyAttributes

Returns the ACME account key attributes

func (*Client) AccountSigner

func (ac *Client) AccountSigner() crypto.Signer

Returns the ACME account key signer

func (*Client) Certificates

func (ac *Client) Certificates(
	authzID acme.AuthzID,
	keyAttrs *keystore.KeyAttributes,
	includeBundle bool,
	crossSigner *CrossSign) ([]*x509.Certificate, error)

Returns the latest certificates from the local datastore. This includes the any cross-signed certificates if they exist.

func (*Client) CrossSign

func (ac *Client) CrossSign(
	csrDER []byte,
	certDER []byte,
	acmeCertRequest CertificateRequest) (*x509.Certificate, error)

Cross-signs a certificate using the client instantiated with the cross-signer DirecotryURL.

func (*Client) CrossSignerFromClient

func (ac *Client) CrossSignerFromClient(crossSigner *CrossSign) (*Client, error)

NewCrossSigningClient creates a new ACME client used to cross-sign a certificate request.

func (*Client) DownloadCertificates

func (ac *Client) DownloadCertificates(
	challengeType string,
	keyAttrs *keystore.KeyAttributes,
	includeBundle bool,
	crossSigner *CrossSign) ([]*x509.Certificate, error)

Downloads the latest certificate from the ACME server, If the certificate is cross-signed, the cross-signed certificate is also downloaded and returned.

func (*Client) EnrollDevice

func (ac *Client) EnrollDevice(
	certRequest ca.CertificateRequest) (*x509.Certificate, error)

Creates a new ACME order for Initial Attestation Key (IAK) and Initial Device Identifier (IDevID) certificates. The EK certificate serial number is used as the "permanent-identifier" authorization value to return a custom "device-01" challenge. In response to the challenge, a TCG-CSR-IDevID Certificate Signing Request is created as specified in Section 13.1 of the TPM 2.0 Keys for Device Identity and Attestation documentation, and the challenge is accepted. Upon notifying the ACME server the challenge is ready to be validated, the ACME server will provide the TCG-CSR-IDEVD using the methods described in the "device-01" challenge type. Upon successful validation, the ACME server fulfills the order and returns the IAK and IDevID certificates in that specific order.

This operation is intended for use by an OEM or Enterprise to enable automated device enrollment via the ACME protocol.

func (*Client) KeyChange

func (ac *Client) KeyChange() error

Perform an ACME key-change operation

func (*Client) RegisterAccount

func (ac *Client) RegisterAccount() (*acme.Account, error)

Registers a new account with the ACME server using the account email provided by the platform configuration file

func (*Client) RegisterAccountWithEmail

func (ac *Client) RegisterAccountWithEmail(email string) (*acme.Account, error)

Registers a new account with the ACME server using the provided email address

func (*Client) RequestCertificate

func (ac *Client) RequestCertificate(
	acmeCertRequest CertificateRequest,
	createKey bool) (cert *x509.Certificate, xsignedCert *x509.Certificate, err error)

Creates a new ACME TLS certificate order using the provided authorization and challenge types. Upon successful authorization and challenge resolution, the requested certificate is returned in ASN.1 DER form.

func (*Client) RequestEndorsementKeyCertificate

func (ac *Client) RequestEndorsementKeyCertificate(
	certRequest ca.CertificateRequest) (*x509.Certificate, error)

Requests a new TPM Endorsement Key (EK) Certificate. This operation supports use cases where a TPM Manufacturer failed to pre-install an Endorsement Key Certificate in the TPM during manufacturing per TGC specifications, TPM simulators without an EK Cert, or any case that replaces the EK Cert with an OEM, Administrator or User generated EK Cert.

NOTE: There is no way for the ACME server to prove or guarantee the EK provided in this request is a real EK in a genuine TPM. The endorse-01 challenge and subsequent EK Certificate issuance is provided as an OEM provisioning feature that places trust in the ACME server endpoint security and permissions granted to the user making this request.

type ClientConfig

type ClientConfig struct {
	Account             *AccountConfig `yaml:"account" json:"account" mapstructure:"account"`
	ConsistencyLevel    string         `yaml:"consistency" json:"consistency" mapstructure:"consistency"`
	DirectoryURL        string         `yaml:"directory" json:"directory" mapstructure:"directory"`
	Enrollment          *Enrollment    `yaml:"enrollment" json:"enrollment" mapstructure:"enrollment"`
	Subject             *ca.Subject    `yaml:"subject" json:"subject" mapstructure:"subject"`
	RequestServerBundle bool           `yaml:"request-server-bundle" json:"request_server_bundle" mapstructure:"request-server-bundle"`
}

type Config

type Config struct {
	Client *ClientConfig `yaml:"client" json:"client" mapstructure:"client"`
	Server *ServerConfig `yaml:"server" json:"server" mapstructure:"server"`
}

type CrossSign

type CrossSign struct {
	DirectoryURL  string `yaml:"directory" json:"directory" mapstructure:"directory"`
	ChallengeType string `yaml:"challenge" json:"challenge" mapstructure:"challenge"`
}

type Directory

type Directory struct {
	NewNonce   string `json:"newNonce"`
	NewAccount string `json:"newAccount"`
	NewOrder   string `json:"newOrder"`
	RevokeCert string `json:"revokeCert"`
	KeyChange  string `json:"keyChange"`
	Meta       Meta   `json:"meta"`
}

Directory provides the ACME server's directory endpoints as per RFC 8555.

type Enrollment

type Enrollment struct {
	Challenge string `yaml:"challenge" json:"challenge" mapstructure:"challenge"`
	IPAddress string `yaml:"ip" json:"ip" mapstructure:"ip"`
}

type Meta

type Meta struct {
	TermsOfService     string   `json:"termsOfService,omitempty"`
	Website            string   `json:"website,omitempty"`
	CAAIdentities      []string `json:"caaIdentities,omitempty"`
	ExternalAccountReq bool     `json:"externalAccountRequired,omitempty"`
}

Meta provides additional information about the ACME server.

type Nonce

type Nonce struct {
	// contains filtered or unexported fields
}

func NewNonce

func NewNonce(nonce []byte) *Nonce

func (*Nonce) Nonce

func (n *Nonce) Nonce() (string, error)

type NonceStore

type NonceStore struct {
	// contains filtered or unexported fields
}

NonceStore is a thread-safe store for nonces

func NewNonceStore

func NewNonceStore(ttl time.Duration) *NonceStore

NewNonceStore initializes a new NonceStore with a specified TTL (Time-To-Live)

func (*NonceStore) Add

func (s *NonceStore) Add(nonce string)

Add inserts a new nonce into the store with the current timestamp

func (*NonceStore) Exists

func (s *NonceStore) Exists(nonce string) bool

Exists checks if a nonce exists and is still valid (not expired) Returns true if valid, false otherwise

type ServerConfig

type ServerConfig struct {
	DirectoryURL   string   `yaml:"directory" json:"directory" mapstructure:"directory"`
	Challenges     []string `yaml:"challenges" json:"challenges" mapstructure:"challenges"`
	TermsOfService string   `yaml:"terms-of-service" json:"terms_of_service" mapstructure:"terms-of-service"`
}

Directories

Path Synopsis
challenge
dao

Jump to

Keyboard shortcuts

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