2021-07-23 13:41:24 +00:00
package api
import (
2021-09-16 21:09:24 +00:00
"context"
2021-12-09 08:36:03 +00:00
"fmt"
2021-07-23 13:41:24 +00:00
"net/http"
2021-08-27 12:10:00 +00:00
"github.com/go-chi/chi"
2022-03-30 08:22:22 +00:00
"go.step.sm/linkedca"
"github.com/smallstep/certificates/api/render"
2021-07-23 13:41:24 +00:00
"github.com/smallstep/certificates/authority/admin"
2021-09-16 21:09:24 +00:00
"github.com/smallstep/certificates/authority/provisioner"
2021-07-23 13:41:24 +00:00
)
2022-01-07 15:59:55 +00:00
const (
// provisionerContextKey provisioner key
provisionerContextKey = ContextKey ( "provisioner" )
)
2021-07-23 13:41:24 +00:00
// CreateExternalAccountKeyRequest is the type for POST /admin/acme/eab requests
type CreateExternalAccountKeyRequest struct {
2021-10-08 12:29:44 +00:00
Reference string ` json:"reference" `
2021-07-23 13:41:24 +00:00
}
2021-09-16 21:09:24 +00:00
// Validate validates a new ACME EAB Key request body.
2021-08-27 10:39:37 +00:00
func ( r * CreateExternalAccountKeyRequest ) Validate ( ) error {
2021-12-09 08:36:03 +00:00
if len ( r . Reference ) > 256 { // an arbitrary, but sensible (IMO), limit
return fmt . Errorf ( "reference length %d exceeds the maximum (256)" , len ( r . Reference ) )
}
2021-08-27 10:39:37 +00:00
return nil
2021-07-23 13:41:24 +00:00
}
// GetExternalAccountKeysResponse is the type for GET /admin/acme/eab responses
type GetExternalAccountKeysResponse struct {
2022-01-24 13:03:56 +00:00
EAKs [ ] * linkedca . EABKey ` json:"eaks" `
NextCursor string ` json:"nextCursor" `
2021-07-23 13:41:24 +00:00
}
2021-10-08 12:29:44 +00:00
// requireEABEnabled is a middleware that ensures ACME EAB is enabled
// before serving requests that act on ACME EAB credentials.
2022-04-27 18:59:32 +00:00
func requireEABEnabled ( next nextHTTP ) nextHTTP {
2021-10-08 12:29:44 +00:00
return func ( w http . ResponseWriter , r * http . Request ) {
2022-01-07 15:59:55 +00:00
ctx := r . Context ( )
2022-01-24 13:03:56 +00:00
provName := chi . URLParam ( r , "provisionerName" )
2022-04-27 18:59:32 +00:00
eabEnabled , prov , err := provisionerHasEABEnabled ( ctx , provName )
2021-10-08 12:29:44 +00:00
if err != nil {
2022-03-30 08:22:22 +00:00
render . Error ( w , err )
2021-10-08 12:29:44 +00:00
return
}
if ! eabEnabled {
2022-03-30 08:22:22 +00:00
render . Error ( w , admin . NewError ( admin . ErrorBadRequestType , "ACME EAB not enabled for provisioner %s" , prov . GetName ( ) ) )
2021-10-08 12:29:44 +00:00
return
}
2022-01-07 15:59:55 +00:00
ctx = context . WithValue ( ctx , provisionerContextKey , prov )
next ( w , r . WithContext ( ctx ) )
2021-10-08 12:29:44 +00:00
}
}
2021-09-16 21:09:24 +00:00
// provisionerHasEABEnabled determines if the "requireEAB" setting for an ACME
// provisioner is set to true and thus has EAB enabled.
2022-04-27 18:59:32 +00:00
func provisionerHasEABEnabled ( ctx context . Context , provisionerName string ) ( bool , * linkedca . Provisioner , error ) {
2021-09-16 21:09:24 +00:00
var (
p provisioner . Interface
err error
)
2022-04-27 18:59:32 +00:00
auth := mustAuthority ( ctx )
db := admin . MustFromContext ( ctx )
if p , err = auth . LoadProvisionerByName ( provisionerName ) ; err != nil {
2022-01-07 15:59:55 +00:00
return false , nil , admin . WrapErrorISE ( err , "error loading provisioner %s" , provisionerName )
2021-09-16 21:09:24 +00:00
}
2022-04-27 18:59:32 +00:00
prov , err := db . GetProvisioner ( ctx , p . GetID ( ) )
2021-09-16 21:09:24 +00:00
if err != nil {
2022-01-07 15:59:55 +00:00
return false , nil , admin . WrapErrorISE ( err , "error getting provisioner with ID: %s" , p . GetID ( ) )
2021-09-16 21:09:24 +00:00
}
details := prov . GetDetails ( )
if details == nil {
2022-01-07 15:59:55 +00:00
return false , nil , admin . NewErrorISE ( "error getting details for provisioner with ID: %s" , p . GetID ( ) )
2021-09-16 21:09:24 +00:00
}
2021-10-11 21:34:23 +00:00
acmeProvisioner := details . GetACME ( )
if acmeProvisioner == nil {
2022-01-07 15:59:55 +00:00
return false , nil , admin . NewErrorISE ( "error getting ACME details for provisioner with ID: %s" , p . GetID ( ) )
2021-09-16 21:09:24 +00:00
}
2022-01-07 15:59:55 +00:00
return acmeProvisioner . GetRequireEab ( ) , prov , nil
}
2022-02-08 12:26:30 +00:00
type acmeAdminResponderInterface interface {
GetExternalAccountKeys ( w http . ResponseWriter , r * http . Request )
CreateExternalAccountKey ( w http . ResponseWriter , r * http . Request )
DeleteExternalAccountKey ( w http . ResponseWriter , r * http . Request )
2021-09-16 21:09:24 +00:00
}
2022-02-08 12:26:30 +00:00
// ACMEAdminResponder is responsible for writing ACME admin responses
type ACMEAdminResponder struct { }
2021-07-23 13:41:24 +00:00
2022-02-08 12:26:30 +00:00
// NewACMEAdminResponder returns a new ACMEAdminResponder
func NewACMEAdminResponder ( ) * ACMEAdminResponder {
return & ACMEAdminResponder { }
2021-07-23 13:41:24 +00:00
}
2022-02-08 12:26:30 +00:00
// GetExternalAccountKeys writes the response for the EAB keys GET endpoint
func ( h * ACMEAdminResponder ) GetExternalAccountKeys ( w http . ResponseWriter , r * http . Request ) {
2022-03-30 08:22:22 +00:00
render . Error ( w , admin . NewError ( admin . ErrorNotImplementedType , "this functionality is currently only available in Certificate Manager: https://u.step.sm/cm" ) )
2021-08-27 12:10:00 +00:00
}
2022-02-08 12:26:30 +00:00
// CreateExternalAccountKey writes the response for the EAB key POST endpoint
func ( h * ACMEAdminResponder ) CreateExternalAccountKey ( w http . ResponseWriter , r * http . Request ) {
2022-03-30 08:22:22 +00:00
render . Error ( w , admin . NewError ( admin . ErrorNotImplementedType , "this functionality is currently only available in Certificate Manager: https://u.step.sm/cm" ) )
2022-02-08 12:26:30 +00:00
}
2021-08-27 14:58:04 +00:00
2022-02-08 12:26:30 +00:00
// DeleteExternalAccountKey writes the response for the EAB key DELETE endpoint
func ( h * ACMEAdminResponder ) DeleteExternalAccountKey ( w http . ResponseWriter , r * http . Request ) {
2022-03-30 08:22:22 +00:00
render . Error ( w , admin . NewError ( admin . ErrorNotImplementedType , "this functionality is currently only available in Certificate Manager: https://u.step.sm/cm" ) )
2021-07-23 13:41:24 +00:00
}