b4edc81cd5
* Distinguish POST-as-GET from POST-with-empty-body Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Add ACME authorization, identifier, and challenge types Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Add ability to load and save authorizations Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Add ACME authorizations path handling This supports two methods: a fetch handler over the authorization, to expose the underlying challenges, and a deactivate handler to revoke the authorization and mark its challenges invalid. Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Add ACME challenge path handling These paths kick off processing and validation of the challenge by the ACME client. Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> --------- Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
124 lines
3.1 KiB
Go
124 lines
3.1 KiB
Go
package pki
|
|
|
|
import (
|
|
"time"
|
|
)
|
|
|
|
type ACMEIdentifierType string
|
|
|
|
const (
|
|
ACMEDNSIdentifier ACMEIdentifierType = "dns"
|
|
ACMEIPIdentifier ACMEIdentifierType = "ip"
|
|
)
|
|
|
|
type ACMEIdentifier struct {
|
|
Type ACMEIdentifierType `json:"type"`
|
|
Value string `json:"value"`
|
|
}
|
|
|
|
type ACMEAuthorizationStatusType string
|
|
|
|
const (
|
|
ACMEAuthorizationPending ACMEAuthorizationStatusType = "pending"
|
|
ACMEAuthorizationValid ACMEAuthorizationStatusType = "valid"
|
|
ACMEAuthorizationInvalid ACMEAuthorizationStatusType = "invalid"
|
|
ACMEAuthorizationDeactivated ACMEAuthorizationStatusType = "deactivated"
|
|
ACMEAuthorizationExpired ACMEAuthorizationStatusType = "expired"
|
|
ACMEAuthorizationRevoked ACMEAuthorizationStatusType = "revoked"
|
|
)
|
|
|
|
type ACMEChallengeType string
|
|
|
|
const (
|
|
ACMEHTTPChallenge ACMEChallengeType = "http-01"
|
|
ACMEDNSChallenge ACMEChallengeType = "dns-01"
|
|
ACMEALPNChallenge ACMEChallengeType = "tls-alpn-01"
|
|
)
|
|
|
|
type ACMEChallengeStatusType string
|
|
|
|
const (
|
|
ACMEChallengePending ACMEChallengeStatusType = "pending"
|
|
ACMEChallengeProcessing ACMEChallengeStatusType = "processing"
|
|
ACMEChallengeValid ACMEChallengeStatusType = "valid"
|
|
ACMEChallengeInvalid ACMEChallengeStatusType = "invalid"
|
|
)
|
|
|
|
type ACMEChallenge struct {
|
|
Type ACMEChallengeType `json:"type"`
|
|
URL string `json:"url"`
|
|
Status ACMEChallengeStatusType `json:"status"`
|
|
Validated string `json:"validated,optional"`
|
|
Error map[string]interface{} `json:"error,optional"`
|
|
ChallengeFields map[string]interface{} `json:"challenge_fields"`
|
|
}
|
|
|
|
func (ac *ACMEChallenge) NetworkMarshal() map[string]interface{} {
|
|
resp := map[string]interface{}{
|
|
"type": ac.Type,
|
|
"url": ac.URL,
|
|
"status": ac.Status,
|
|
}
|
|
|
|
if ac.Validated != "" {
|
|
resp["validated"] = ac.Validated
|
|
}
|
|
|
|
if len(ac.Error) > 0 {
|
|
resp["error"] = ac.Error
|
|
}
|
|
|
|
for field, value := range ac.ChallengeFields {
|
|
resp[field] = value
|
|
}
|
|
|
|
return resp
|
|
}
|
|
|
|
type ACMEAuthorization struct {
|
|
Id string `json:"id"`
|
|
AccountId string `json:"account_id"`
|
|
|
|
Identifier *ACMEIdentifier `json:"identifier"`
|
|
Status ACMEAuthorizationStatusType `json:"status"`
|
|
|
|
// Per RFC 8555 Section 7.1.4. Authorization Objects:
|
|
//
|
|
// > This field is REQUIRED for objects with "valid" in the "status"
|
|
// > field.
|
|
Expires string `json:"expires,optional"`
|
|
|
|
Challenges []*ACMEChallenge `json:"challenges"`
|
|
Wildcard bool `json:"wildcard"`
|
|
}
|
|
|
|
func (aa *ACMEAuthorization) GetExpires() (time.Time, error) {
|
|
if aa.Expires == "" {
|
|
return time.Time{}, nil
|
|
}
|
|
|
|
return time.Parse(time.RFC3339, aa.Expires)
|
|
}
|
|
|
|
func (aa *ACMEAuthorization) NetworkMarshal() map[string]interface{} {
|
|
resp := map[string]interface{}{
|
|
"identifier": aa.Identifier,
|
|
"status": aa.Status,
|
|
"wildcard": aa.Wildcard,
|
|
}
|
|
|
|
if aa.Expires != "" {
|
|
resp["expires"] = aa.Expires
|
|
}
|
|
|
|
if len(aa.Challenges) > 0 {
|
|
challenges := []map[string]interface{}{}
|
|
for _, challenge := range aa.Challenges {
|
|
challenges = append(challenges, challenge.NetworkMarshal())
|
|
}
|
|
resp["challenges"] = challenges
|
|
}
|
|
|
|
return resp
|
|
}
|