commons.go raw

   1  // Package acme contains all objects related the ACME endpoints.
   2  // https://www.rfc-editor.org/rfc/rfc8555.html
   3  package acme
   4  
   5  import (
   6  	"encoding/json"
   7  	"time"
   8  )
   9  
  10  // ACME status values of Account, Order, Authorization and Challenge objects.
  11  // See https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.6 for details.
  12  const (
  13  	StatusDeactivated = "deactivated"
  14  	StatusExpired     = "expired"
  15  	StatusInvalid     = "invalid"
  16  	StatusPending     = "pending"
  17  	StatusProcessing  = "processing"
  18  	StatusReady       = "ready"
  19  	StatusRevoked     = "revoked"
  20  	StatusUnknown     = "unknown"
  21  	StatusValid       = "valid"
  22  )
  23  
  24  // CRL reason codes as defined in RFC 5280.
  25  // https://datatracker.ietf.org/doc/html/rfc5280#section-5.3.1
  26  const (
  27  	CRLReasonUnspecified          uint = 0
  28  	CRLReasonKeyCompromise        uint = 1
  29  	CRLReasonCACompromise         uint = 2
  30  	CRLReasonAffiliationChanged   uint = 3
  31  	CRLReasonSuperseded           uint = 4
  32  	CRLReasonCessationOfOperation uint = 5
  33  	CRLReasonCertificateHold      uint = 6
  34  	CRLReasonRemoveFromCRL        uint = 8
  35  	CRLReasonPrivilegeWithdrawn   uint = 9
  36  	CRLReasonAACompromise         uint = 10
  37  )
  38  
  39  // Directory the ACME directory object.
  40  // - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.1
  41  // - https://www.rfc-editor.org/rfc/rfc9773.html
  42  type Directory struct {
  43  	NewNonceURL   string `json:"newNonce"`
  44  	NewAccountURL string `json:"newAccount"`
  45  	NewOrderURL   string `json:"newOrder"`
  46  	NewAuthzURL   string `json:"newAuthz"`
  47  	RevokeCertURL string `json:"revokeCert"`
  48  	KeyChangeURL  string `json:"keyChange"`
  49  	Meta          Meta   `json:"meta"`
  50  	RenewalInfo   string `json:"renewalInfo"`
  51  }
  52  
  53  // Meta the ACME meta object (related to Directory).
  54  // - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.1
  55  type Meta struct {
  56  	// termsOfService (optional, string):
  57  	// A URL identifying the current terms of service.
  58  	TermsOfService string `json:"termsOfService"`
  59  
  60  	// website (optional, string):
  61  	// An HTTP or HTTPS URL locating a website providing more information about the ACME server.
  62  	Website string `json:"website"`
  63  
  64  	// caaIdentities (optional, array of string):
  65  	// The hostnames that the ACME server recognizes as referring to itself
  66  	// for the purposes of CAA record validation as defined in [RFC6844].
  67  	// Each string MUST represent the same sequence of ASCII code points
  68  	// that the server will expect to see as the "Issuer Domain Name" in a CAA issue or issuewild property tag.
  69  	// This allows clients to determine the correct issuer domain name to use when configuring CAA records.
  70  	CaaIdentities []string `json:"caaIdentities"`
  71  
  72  	// externalAccountRequired (optional, boolean):
  73  	// If this field is present and set to "true",
  74  	// then the CA requires that all new-account requests include an "externalAccountBinding" field
  75  	// associating the new account with an external account.
  76  	ExternalAccountRequired bool `json:"externalAccountRequired"`
  77  
  78  	// profiles (optional, object):
  79  	// A map of profile names to human-readable descriptions of those profiles.
  80  	// https://www.ietf.org/id/draft-ietf-acme-profiles-00.html#section-3
  81  	Profiles map[string]string `json:"profiles"`
  82  }
  83  
  84  // ExtendedAccount an extended Account.
  85  type ExtendedAccount struct {
  86  	Account
  87  
  88  	// Contains the value of the response header `Location`
  89  	Location string `json:"-"`
  90  }
  91  
  92  // Account the ACME account Object.
  93  // - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.2
  94  // - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.3
  95  type Account struct {
  96  	// status (required, string):
  97  	// The status of this account.
  98  	// Possible values are: "valid", "deactivated", and "revoked".
  99  	// The value "deactivated" should be used to indicate client-initiated deactivation
 100  	// whereas "revoked" should be used to indicate server-initiated deactivation. (See Section 7.1.6)
 101  	Status string `json:"status,omitempty"`
 102  
 103  	// contact (optional, array of string):
 104  	// An array of URLs that the server can use to contact the client for issues related to this account.
 105  	// For example, the server may wish to notify the client about server-initiated revocation or certificate expiration.
 106  	// For information on supported URL schemes, see Section 7.3
 107  	Contact []string `json:"contact,omitempty"`
 108  
 109  	// termsOfServiceAgreed (optional, boolean):
 110  	// Including this field in a new-account request,
 111  	// with a value of true, indicates the client's agreement with the terms of service.
 112  	// This field is not updateable by the client.
 113  	TermsOfServiceAgreed bool `json:"termsOfServiceAgreed,omitempty"`
 114  
 115  	// orders (required, string):
 116  	// A URL from which a list of orders submitted by this account can be fetched via a POST-as-GET request,
 117  	// as described in Section 7.1.2.1.
 118  	Orders string `json:"orders,omitempty"`
 119  
 120  	// onlyReturnExisting (optional, boolean):
 121  	// If this field is present with the value "true",
 122  	// then the server MUST NOT create a new account if one does not already exist.
 123  	// This allows a client to look up an account URL based on an account key (see Section 7.3.1).
 124  	OnlyReturnExisting bool `json:"onlyReturnExisting,omitempty"`
 125  
 126  	// externalAccountBinding (optional, object):
 127  	// An optional field for binding the new account with an existing non-ACME account (see Section 7.3.4).
 128  	ExternalAccountBinding json.RawMessage `json:"externalAccountBinding,omitempty"`
 129  }
 130  
 131  // ExtendedOrder a extended Order.
 132  type ExtendedOrder struct {
 133  	Order
 134  
 135  	// The order URL, contains the value of the response header `Location`
 136  	Location string `json:"-"`
 137  }
 138  
 139  // Order the ACME order Object.
 140  // - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.3
 141  type Order struct {
 142  	// status (required, string):
 143  	// The status of this order.
 144  	// Possible values are: "pending", "ready", "processing", "valid", and "invalid".
 145  	Status string `json:"status,omitempty"`
 146  
 147  	// expires (optional, string):
 148  	// The timestamp after which the server will consider this order invalid,
 149  	// encoded in the format specified in RFC 3339 [RFC3339].
 150  	// This field is REQUIRED for objects with "pending" or "valid" in the status field.
 151  	Expires string `json:"expires,omitempty"`
 152  
 153  	// identifiers (required, array of object):
 154  	// An array of identifier objects that the order pertains to.
 155  	Identifiers []Identifier `json:"identifiers"`
 156  
 157  	// profile (string, optional):
 158  	// A string uniquely identifying the profile
 159  	// which will be used to affect issuance of the certificate requested by this Order.
 160  	// https://www.ietf.org/id/draft-ietf-acme-profiles-00.html#section-4
 161  	Profile string `json:"profile,omitempty"`
 162  
 163  	// notBefore (optional, string):
 164  	// The requested value of the notBefore field in the certificate,
 165  	// in the date format defined in [RFC3339].
 166  	NotBefore string `json:"notBefore,omitempty"`
 167  
 168  	// notAfter (optional, string):
 169  	// The requested value of the notAfter field in the certificate,
 170  	// in the date format defined in [RFC3339].
 171  	NotAfter string `json:"notAfter,omitempty"`
 172  
 173  	// error (optional, object):
 174  	// The error that occurred while processing the order, if any.
 175  	// This field is structured as a problem document [RFC7807].
 176  	Error *ProblemDetails `json:"error,omitempty"`
 177  
 178  	// authorizations (required, array of string):
 179  	// For pending orders,
 180  	// the authorizations that the client needs to complete before the requested certificate can be issued (see Section 7.5),
 181  	// including unexpired authorizations that the client has completed in the past for identifiers specified in the order.
 182  	// The authorizations required are dictated by server policy
 183  	// and there may not be a 1:1 relationship between the order identifiers and the authorizations required.
 184  	// For final orders (in the "valid" or "invalid" state), the authorizations that were completed.
 185  	// Each entry is a URL from which an authorization can be fetched with a POST-as-GET request.
 186  	Authorizations []string `json:"authorizations,omitempty"`
 187  
 188  	// finalize (required, string):
 189  	// A URL that a CSR must be POSTed to once all of the order's authorizations are satisfied to finalize the order.
 190  	// The result of a successful finalization will be the population of the certificate URL for the order.
 191  	Finalize string `json:"finalize,omitempty"`
 192  
 193  	// certificate (optional, string):
 194  	// A URL for the certificate that has been issued in response to this order
 195  	Certificate string `json:"certificate,omitempty"`
 196  
 197  	// replaces (optional, string):
 198  	// replaces (string, optional): A string uniquely identifying a
 199  	// previously-issued certificate which this order is intended to replace.
 200  	// - https://www.rfc-editor.org/rfc/rfc9773.html#section-5
 201  	Replaces string `json:"replaces,omitempty"`
 202  }
 203  
 204  func (r *Order) Err() error {
 205  	if r.Error != nil {
 206  		return r.Error
 207  	}
 208  
 209  	return nil
 210  }
 211  
 212  // Authorization the ACME authorization object.
 213  // - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.4
 214  type Authorization struct {
 215  	// status (required, string):
 216  	// The status of this authorization.
 217  	// Possible values are: "pending", "valid", "invalid", "deactivated", "expired", and "revoked".
 218  	Status string `json:"status"`
 219  
 220  	// expires (optional, string):
 221  	// The timestamp after which the server will consider this authorization invalid,
 222  	// encoded in the format specified in RFC 3339 [RFC3339].
 223  	// This field is REQUIRED for objects with "valid" in the "status" field.
 224  	Expires time.Time `json:"expires,omitzero"`
 225  
 226  	// identifier (required, object):
 227  	// The identifier that the account is authorized to represent
 228  	Identifier Identifier `json:"identifier"`
 229  
 230  	// challenges (required, array of objects):
 231  	// For pending authorizations, the challenges that the client can fulfill in order to prove possession of the identifier.
 232  	// For valid authorizations, the challenge that was validated.
 233  	// For invalid authorizations, the challenge that was attempted and failed.
 234  	// Each array entry is an object with parameters required to validate the challenge.
 235  	// A client should attempt to fulfill one of these challenges,
 236  	// and a server should consider any one of the challenges sufficient to make the authorization valid.
 237  	Challenges []Challenge `json:"challenges,omitempty"`
 238  
 239  	// wildcard (optional, boolean):
 240  	// For authorizations created as a result of a newOrder request containing a DNS identifier
 241  	// with a value that contained a wildcard prefix this field MUST be present, and true.
 242  	Wildcard bool `json:"wildcard,omitempty"`
 243  }
 244  
 245  // ExtendedChallenge a extended Challenge.
 246  type ExtendedChallenge struct {
 247  	Challenge
 248  
 249  	// Contains the value of the response header `Retry-After`
 250  	RetryAfter string `json:"-"`
 251  	// Contains the value of the response header `Link` rel="up"
 252  	AuthorizationURL string `json:"-"`
 253  }
 254  
 255  // Challenge the ACME challenge object.
 256  // - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.5
 257  // - https://www.rfc-editor.org/rfc/rfc8555.html#section-8
 258  type Challenge struct {
 259  	// type (required, string):
 260  	// The type of challenge encoded in the object.
 261  	Type string `json:"type"`
 262  
 263  	// url (required, string):
 264  	// The URL to which a response can be posted.
 265  	URL string `json:"url"`
 266  
 267  	// status (required, string):
 268  	// The status of this challenge. Possible values are: "pending", "processing", "valid", and "invalid".
 269  	Status string `json:"status"`
 270  
 271  	// validated (optional, string):
 272  	// The time at which the server validated this challenge,
 273  	// encoded in the format specified in RFC 3339 [RFC3339].
 274  	// This field is REQUIRED if the "status" field is "valid".
 275  	Validated time.Time `json:"validated,omitzero"`
 276  
 277  	// error (optional, object):
 278  	// Error that occurred while the server was validating the challenge, if any,
 279  	// structured as a problem document [RFC7807].
 280  	// Multiple errors can be indicated by using subproblems Section 6.7.1.
 281  	// A challenge object with an error MUST have status equal to "invalid".
 282  	Error *ProblemDetails `json:"error,omitempty"`
 283  
 284  	// token (required, string):
 285  	// A random value that uniquely identifies the challenge.
 286  	// This value MUST have at least 128 bits of entropy.
 287  	// It MUST NOT contain any characters outside the base64url alphabet,
 288  	// and MUST NOT include base64 padding characters ("=").
 289  	// See [RFC4086] for additional information on randomness requirements.
 290  	// https://www.rfc-editor.org/rfc/rfc8555.html#section-8.3
 291  	// https://www.rfc-editor.org/rfc/rfc8555.html#section-8.4
 292  	Token string `json:"token"`
 293  
 294  	// https://www.rfc-editor.org/rfc/rfc8555.html#section-8.1
 295  	KeyAuthorization string `json:"keyAuthorization"`
 296  }
 297  
 298  func (c *Challenge) Err() error {
 299  	if c.Error != nil {
 300  		return c.Error
 301  	}
 302  
 303  	return nil
 304  }
 305  
 306  // Identifier the ACME identifier object.
 307  // - https://www.rfc-editor.org/rfc/rfc8555.html#section-9.7.7
 308  type Identifier struct {
 309  	Type  string `json:"type"`
 310  	Value string `json:"value"`
 311  }
 312  
 313  // CSRMessage Certificate Signing Request.
 314  // - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.4
 315  type CSRMessage struct {
 316  	// csr (required, string):
 317  	// A CSR encoding the parameters for the certificate being requested [RFC2986].
 318  	// The CSR is sent in the base64url-encoded version of the DER format.
 319  	// (Note: Because this field uses base64url, and does not include headers, it is different from PEM.).
 320  	Csr string `json:"csr"`
 321  }
 322  
 323  // RevokeCertMessage a certificate revocation message.
 324  // - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.6
 325  // - https://www.rfc-editor.org/rfc/rfc5280.html#section-5.3.1
 326  type RevokeCertMessage struct {
 327  	// certificate (required, string):
 328  	// The certificate to be revoked, in the base64url-encoded version of the DER format.
 329  	// (Note: Because this field uses base64url, and does not include headers, it is different from PEM.)
 330  	Certificate string `json:"certificate"`
 331  
 332  	// reason (optional, int):
 333  	// One of the revocation reasonCodes defined in Section 5.3.1 of [RFC5280] to be used when generating OCSP responses and CRLs.
 334  	// If this field is not set the server SHOULD omit the reasonCode CRL entry extension when generating OCSP responses and CRLs.
 335  	// The server MAY disallow a subset of reasonCodes from being used by the user.
 336  	// If a request contains a disallowed reasonCode the server MUST reject it with the error type "urn:ietf:params:acme:error:badRevocationReason".
 337  	// The problem document detail SHOULD indicate which reasonCodes are allowed.
 338  	Reason *uint `json:"reason,omitempty"`
 339  }
 340  
 341  // RawCertificate raw data of a certificate.
 342  type RawCertificate struct {
 343  	Cert   []byte
 344  	Issuer []byte
 345  }
 346  
 347  // Window is a window of time.
 348  type Window struct {
 349  	Start time.Time `json:"start"`
 350  	End   time.Time `json:"end"`
 351  }
 352  
 353  // RenewalInfoResponse is the response to GET requests made the renewalInfo endpoint.
 354  // - (4.1. Getting Renewal Information) https://www.rfc-editor.org/rfc/rfc9773.html
 355  type RenewalInfoResponse struct {
 356  	// SuggestedWindow contains two fields, start and end,
 357  	// whose values are timestamps which bound the window of time in which the CA recommends renewing the certificate.
 358  	SuggestedWindow Window `json:"suggestedWindow"`
 359  	//	ExplanationURL is an optional URL pointing to a page which may explain why the suggested renewal window is what it is.
 360  	//	For example, it may be a page explaining the CA's dynamic load-balancing strategy,
 361  	//	or a page documenting which certificates are affected by a mass revocation event.
 362  	//	Callers SHOULD provide this URL to their operator, if present.
 363  	ExplanationURL string `json:"explanationURL"`
 364  }
 365  
 366  // RenewalInfoUpdateRequest is the JWS payload for POST requests made to the renewalInfo endpoint.
 367  // - (4.2. RenewalInfo Objects) https://www.rfc-editor.org/rfc/rfc9773.html#section-4.2
 368  type RenewalInfoUpdateRequest struct {
 369  	// CertID is a composite string in the format: base64url(AKI) || '.' || base64url(Serial), where AKI is the
 370  	// certificate's authority key identifier and Serial is the certificate's serial number. For details, see:
 371  	// https://www.rfc-editor.org/rfc/rfc9773.html#section-4.1
 372  	CertID string `json:"certID"`
 373  	// Replaced is required and indicates whether or not the client considers the certificate to have been replaced.
 374  	// A certificate is considered replaced when its revocation would not disrupt any ongoing services,
 375  	// for instance because it has been renewed and the new certificate is in use, or because it is no longer in use.
 376  	// Clients SHOULD NOT send a request where this value is false.
 377  	Replaced bool `json:"replaced"`
 378  }
 379