2021-02-25 18:24:24 +00:00
package acme
import (
2021-03-01 06:49:20 +00:00
"crypto"
"encoding/base64"
2021-02-25 18:24:24 +00:00
"encoding/json"
2021-07-17 15:35:44 +00:00
"time"
2021-02-25 18:24:24 +00:00
"go.step.sm/crypto/jose"
2022-04-11 13:25:55 +00:00
"github.com/smallstep/certificates/authority/policy"
2021-02-25 18:24:24 +00:00
)
// Account is a subset of the internal account type containing only those
// attributes required for responses in the ACME protocol.
type Account struct {
2021-07-17 17:02:47 +00:00
ID string ` json:"-" `
Key * jose . JSONWebKey ` json:"-" `
Contact [ ] string ` json:"contact,omitempty" `
Status Status ` json:"status" `
OrdersURL string ` json:"orders" `
ExternalAccountBinding interface { } ` json:"externalAccountBinding,omitempty" `
2023-06-07 06:37:51 +00:00
LocationPrefix string ` json:"-" `
ProvisionerName string ` json:"-" `
}
// GetLocation returns the URL location of the given account.
func ( a * Account ) GetLocation ( ) string {
if a . LocationPrefix == "" {
return ""
}
return a . LocationPrefix + a . ID
2021-02-25 18:24:24 +00:00
}
// ToLog enables response logging.
func ( a * Account ) ToLog ( ) ( interface { } , error ) {
b , err := json . Marshal ( a )
if err != nil {
2021-03-05 07:10:46 +00:00
return nil , WrapErrorISE ( err , "error marshaling account for logging" )
2021-02-25 18:24:24 +00:00
}
return string ( b ) , nil
}
// IsValid returns true if the Account is valid.
func ( a * Account ) IsValid ( ) bool {
2022-08-23 19:43:48 +00:00
return a . Status == StatusValid
2021-02-25 18:24:24 +00:00
}
2021-03-01 06:49:20 +00:00
// KeyToID converts a JWK to a thumbprint.
func KeyToID ( jwk * jose . JSONWebKey ) ( string , error ) {
kid , err := jwk . Thumbprint ( crypto . SHA256 )
if err != nil {
2021-03-05 07:10:46 +00:00
return "" , WrapErrorISE ( err , "error generating jwk thumbprint" )
2021-03-01 06:49:20 +00:00
}
return base64 . RawURLEncoding . EncodeToString ( kid ) , nil
}
2021-07-17 15:35:44 +00:00
2022-04-07 12:11:53 +00:00
// PolicyNames contains ACME account level policy names
type PolicyNames struct {
DNSNames [ ] string ` json:"dns" `
IPRanges [ ] string ` json:"ips" `
}
// X509Policy contains ACME account level X.509 policy
type X509Policy struct {
2022-04-29 13:08:19 +00:00
Allowed PolicyNames ` json:"allow" `
Denied PolicyNames ` json:"deny" `
AllowWildcardNames bool ` json:"allowWildcardNames" `
2022-04-07 12:11:53 +00:00
}
// Policy is an ACME Account level policy
type Policy struct {
X509 X509Policy ` json:"x509" `
}
2022-04-11 13:25:55 +00:00
func ( p * Policy ) GetAllowedNameOptions ( ) * policy . X509NameOptions {
if p == nil {
return nil
}
return & policy . X509NameOptions {
DNSDomains : p . X509 . Allowed . DNSNames ,
IPRanges : p . X509 . Allowed . IPRanges ,
}
}
2023-06-07 06:37:51 +00:00
2022-04-11 13:25:55 +00:00
func ( p * Policy ) GetDeniedNameOptions ( ) * policy . X509NameOptions {
if p == nil {
return nil
}
return & policy . X509NameOptions {
DNSDomains : p . X509 . Denied . DNSNames ,
IPRanges : p . X509 . Denied . IPRanges ,
}
}
2022-04-29 13:08:19 +00:00
// AreWildcardNamesAllowed returns if wildcard names
// like *.example.com are allowed to be signed.
// Defaults to false.
func ( p * Policy ) AreWildcardNamesAllowed ( ) bool {
if p == nil {
return false
}
return p . X509 . AllowWildcardNames
2022-04-19 08:24:52 +00:00
}
2021-10-08 11:18:23 +00:00
// ExternalAccountKey is an ACME External Account Binding key.
2021-07-17 15:35:44 +00:00
type ExternalAccountKey struct {
2022-01-07 15:59:55 +00:00
ID string ` json:"id" `
ProvisionerID string ` json:"provisionerID" `
Reference string ` json:"reference" `
AccountID string ` json:"-" `
2022-04-26 08:15:17 +00:00
HmacKey [ ] byte ` json:"-" `
2022-01-07 15:59:55 +00:00
CreatedAt time . Time ` json:"createdAt" `
BoundAt time . Time ` json:"boundAt,omitempty" `
2022-04-07 12:11:53 +00:00
Policy * Policy ` json:"policy,omitempty" `
2021-07-17 15:35:44 +00:00
}
2021-07-17 17:02:47 +00:00
2021-10-08 11:18:23 +00:00
// AlreadyBound returns whether this EAK is already bound to
// an ACME Account or not.
2021-07-22 21:48:41 +00:00
func ( eak * ExternalAccountKey ) AlreadyBound ( ) bool {
return ! eak . BoundAt . IsZero ( )
}
2021-10-08 11:18:23 +00:00
// BindTo binds the EAK to an Account.
// It returns an error if it's already bound.
func ( eak * ExternalAccountKey ) BindTo ( account * Account ) error {
if eak . AlreadyBound ( ) {
return NewError ( ErrorUnauthorizedType , "external account binding key with id '%s' was already bound to account '%s' on %s" , eak . ID , eak . AccountID , eak . BoundAt )
}
2021-07-17 17:02:47 +00:00
eak . AccountID = account . ID
eak . BoundAt = time . Now ( )
2022-04-26 08:15:17 +00:00
eak . HmacKey = [ ] byte { } // clearing the key bytes; can only be used once
2021-10-08 11:18:23 +00:00
return nil
2021-07-17 17:02:47 +00:00
}