Documentation ¶
Index ¶
- Constants
- Variables
- func AccountDoesNotExist(detail string) *entities.Error
- func AccountExistsError(detail, location string) *entities.Error
- func AlreadyRevoked(detail string) *entities.Error
- func BadAttestationStatement(detail string) *entities.Error
- func BadCSR(detail string) *entities.Error
- func BadNonce(detail string) *entities.Error
- func BadPublicKey(detail string) *entities.Error
- func BadRevocationReason(detail string) *entities.Error
- func BadSignatureAlgorithm(detail string) *entities.Error
- func CAAError(detail string) *entities.Error
- func CompoundError(detail string, subproblems []entities.SubProblem) *entities.Error
- func ConnectionError(detail string) *entities.Error
- func DNSError(detail string) *entities.Error
- func ExternalAccountRequired(detail string) *entities.Error
- func GenerateAccountID(pubKey crypto.PublicKey) uint64
- func GenerateNonce(length int) (string, error)
- func GenerateOrderID(authzID acme.AuthzID) uint64
- func IncorrectResponse(detail string) *entities.Error
- func InvalidContact(detail string) *entities.Error
- func IsEnrollXChallenge(challengeType string) bool
- func IsHTTPxChallenge(challengeType string) bool
- func MalformedError(detail string, subproblems []entities.SubProblem) *entities.Error
- func NewDatastore(logger *logging.Logger, config *datastore.Config) (dao.Factory, error)
- func OrderNotReady(detail string) *entities.Error
- func ParseAuthzIDFromChallengeType(challengeType string) (acme.AuthzID, error)
- func ParseChallengeAsDynamicPortAssignment(challengeType string) (string, string, error)
- func ParseConfiguredChallengeVerifiers(challenges []string) (map[string]ChallengeVerifierFunc, error)
- func RateLimited(detail string) *entities.Error
- func RejectedIdentifier(detail string) *entities.Error
- func ServerInternal(detail string) *entities.Error
- func TLSError(detail string) *entities.Error
- func Unauthorized(detail string) *entities.Error
- func UnsupportedContact(detail string) *entities.Error
- func UnsupportedIdentifier(detail string) *entities.Error
- func UserActionRequired(detail, instance string) *entities.Error
- type AccountConfig
- type AuthzID
- type AuthzType
- type CertificateRequest
- type ChallengeType
- type ChallengeVerifierFunc
- type Client
- func (ac *Client) Account() (*acme.Account, error)
- func (ac *Client) AccountFromEmail(email string) (*acme.Account, error)
- func (ac *Client) AccountID() uint64
- func (ac *Client) AccountKeyAttributes() *keystore.KeyAttributes
- func (ac *Client) AccountSigner() crypto.Signer
- func (ac *Client) Certificates(authzID acme.AuthzID, keyAttrs *keystore.KeyAttributes, includeBundle bool, ...) ([]*x509.Certificate, error)
- func (ac *Client) CrossSign(csrDER []byte, certDER []byte, acmeCertRequest CertificateRequest) (*x509.Certificate, error)
- func (ac *Client) CrossSignerFromClient(crossSigner *CrossSign) (*Client, error)
- func (ac *Client) DownloadCertificates(challengeType string, keyAttrs *keystore.KeyAttributes, includeBundle bool, ...) ([]*x509.Certificate, error)
- func (ac *Client) EnrollDevice(certRequest ca.CertificateRequest) (*x509.Certificate, error)
- func (ac *Client) KeyChange() error
- func (ac *Client) RegisterAccount() (*acme.Account, error)
- func (ac *Client) RegisterAccountWithEmail(email string) (*acme.Account, error)
- func (ac *Client) RequestCertificate(acmeCertRequest CertificateRequest, createKey bool) (cert *x509.Certificate, xsignedCert *x509.Certificate, err error)
- func (ac *Client) RequestEndorsementKeyCertificate(certRequest ca.CertificateRequest) (*x509.Certificate, error)
- type ClientConfig
- type Config
- type CrossSign
- type Directory
- type Enrollment
- type Meta
- type Nonce
- type NonceStore
- type ServerConfig
Constants ¶
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" ErrTypeUnsupportedContact = "unsupportedContact" ErrTypeUnsupportedIdentifier = "unsupportedIdentifier" ErrTypeUserActionRequired = "userActionRequired" ErrTypeAccountExists = "accountExists" )
Error definitions as per RFC 8555
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 ¶
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") )
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 AccountExistsError ¶
func AlreadyRevoked ¶
func BadAttestationStatement ¶
func BadPublicKey ¶
func BadRevocationReason ¶
func BadSignatureAlgorithm ¶
func CompoundError ¶
func CompoundError(detail string, subproblems []entities.SubProblem) *entities.Error
func ConnectionError ¶
func ExternalAccountRequired ¶
func GenerateAccountID ¶
func GenerateNonce ¶
GenerateNonce creates a new secure random nonce encoded in URL-safe Base64 without padding
func GenerateOrderID ¶
func IncorrectResponse ¶
func InvalidContact ¶
func IsEnrollXChallenge ¶
func IsHTTPxChallenge ¶
func MalformedError ¶
func MalformedError(detail string, subproblems []entities.SubProblem) *entities.Error
func NewDatastore ¶
Returns an ACME datastore using the backend specified in the datastore section of the platform configuration file
func OrderNotReady ¶
func ParseChallengeAsDynamicPortAssignment ¶
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 RejectedIdentifier ¶
func ServerInternal ¶
func Unauthorized ¶
func UnsupportedContact ¶
func UnsupportedIdentifier ¶
func UserActionRequired ¶
Types ¶
type AccountConfig ¶
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 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 ¶
Returns the ACME account associated with the account email provided by the platform configuration file
func (*Client) AccountFromEmail ¶
Returns the ACME account associated with the provided email address
func (*Client) AccountKeyAttributes ¶
func (ac *Client) AccountKeyAttributes() *keystore.KeyAttributes
Returns the ACME account key attributes
func (*Client) AccountSigner ¶
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 ¶
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) RegisterAccount ¶
Registers a new account with the ACME server using the account email provided by the platform configuration file
func (*Client) RegisterAccountWithEmail ¶
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 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 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 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