func (r *SSHCheckPrincipalRequest) Validate() error {
	switch {
	case r.Type != provisioner.SSHHostCert:
		return errors.Errorf("unsupported type %s", r.Type)
	case r.Principal == "":
		return errors.New("missing or empty principal")
	default:
		return nil
	}
}
Validate checks the check principal request.
package api
import (
	"context"
	"crypto/x509"
	"encoding/base64"
	"encoding/json"
	"net/http"
	"time"
	"github.com/pkg/errors"
	"github.com/smallstep/certificates/authority"
	"github.com/smallstep/certificates/authority/config"
	"github.com/smallstep/certificates/authority/provisioner"
	"github.com/smallstep/certificates/errs"
	"github.com/smallstep/certificates/templates"
	"golang.org/x/crypto/ssh"
)
type SSHAuthority interface {
	SignSSH(ctx context.Context, key ssh.PublicKey, opts provisioner.SignSSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error)
	RenewSSH(ctx context.Context, cert *ssh.Certificate) (*ssh.Certificate, error)
	RekeySSH(ctx context.Context, cert *ssh.Certificate, key ssh.PublicKey, signOpts ...provisioner.SignOption) (*ssh.Certificate, error)
	SignSSHAddUser(ctx context.Context, key ssh.PublicKey, cert *ssh.Certificate) (*ssh.Certificate, error)
	GetSSHRoots(ctx context.Context) (*config.SSHKeys, error)
	GetSSHFederation(ctx context.Context) (*config.SSHKeys, error)
	GetSSHConfig(ctx context.Context, typ string, data map[string]string) ([]templates.Output, error)
	CheckSSHHost(ctx context.Context, principal string, token string) (bool, error)
	GetSSHHosts(ctx context.Context, cert *x509.Certificate) ([]config.Host, error)
	GetSSHBastion(ctx context.Context, user string, hostname string) (*config.Bastion, error)
}
type SSHSignRequest struct {
	PublicKey        []byte             `json:"publicKey"`  
	OTT              string             `json:"ott"`
	CertType         string             `json:"certType,omitempty"`
	KeyID            string             `json:"keyID,omitempty"`
	Principals       []string           `json:"principals,omitempty"`
	ValidAfter       TimeDuration       `json:"validAfter,omitempty"`
	ValidBefore      TimeDuration       `json:"validBefore,omitempty"`
	AddUserPublicKey []byte             `json:"addUserPublicKey,omitempty"`
	IdentityCSR      CertificateRequest `json:"identityCSR,omitempty"`
	TemplateData     json.RawMessage    `json:"templateData,omitempty"`
}
func (s *SSHSignRequest) Validate() error {
	switch {
	case s.CertType != "" && s.CertType != provisioner.SSHUserCert && s.CertType != provisioner.SSHHostCert:
		return errors.Errorf("unknown certType %s", s.CertType)
	case len(s.PublicKey) == 0:
		return errors.New("missing or empty publicKey")
	case s.OTT == "":
		return errors.New("missing or empty ott")
	default:
		if s.IdentityCSR.CertificateRequest != nil {
			if err := s.IdentityCSR.CertificateRequest.CheckSignature(); err != nil {
				return errors.Wrap(err, "invalid identityCSR")
			}
		}
		return nil
	}
}
type SSHSignResponse struct {
	Certificate         SSHCertificate  `json:"crt"`
	AddUserCertificate  *SSHCertificate `json:"addUserCrt,omitempty"`
	IdentityCertificate []Certificate   `json:"identityCrt,omitempty"`
}
type SSHRootsResponse struct {
	UserKeys []SSHPublicKey `json:"userKey,omitempty"`
	HostKeys []SSHPublicKey `json:"hostKey,omitempty"`
}
type SSHCertificate struct {
	*ssh.Certificate `json:"omitempty"`
}
type SSHGetHostsResponse struct {
	Hosts []config.Host `json:"hosts"`
}
func (c SSHCertificate) MarshalJSON() ([]byte, error) {
	if c.Certificate == nil {
		return []byte("null"), nil
	}
	s := base64.StdEncoding.EncodeToString(c.Certificate.Marshal())
	return []byte(`"` + s + `"`), nil
}
func (c *SSHCertificate) UnmarshalJSON(data []byte) error {
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return errors.Wrap(err, "error decoding certificate")
	}
	if s == "" {
		c.Certificate = nil
		return nil
	}
	certData, err := base64.StdEncoding.DecodeString(s)
	if err != nil {
		return errors.Wrap(err, "error decoding ssh certificate")
	}
	pub, err := ssh.ParsePublicKey(certData)
	if err != nil {
		return errors.Wrap(err, "error parsing ssh certificate")
	}
	cert, ok := pub.(*ssh.Certificate)
	if !ok {
		return errors.Errorf("error decoding ssh certificate: %T is not an *ssh.Certificate", pub)
	}
	c.Certificate = cert
	return nil
}
type SSHPublicKey struct {
	ssh.PublicKey
}
func (p *SSHPublicKey) MarshalJSON() ([]byte, error) {
	if p == nil || p.PublicKey == nil {
		return []byte("null"), nil
	}
	s := base64.StdEncoding.EncodeToString(p.PublicKey.Marshal())
	return []byte(`"` + s + `"`), nil
}
func (p *SSHPublicKey) UnmarshalJSON(data []byte) error {
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return errors.Wrap(err, "error decoding ssh public key")
	}
	if s == "" {
		p.PublicKey = nil
		return nil
	}
	data, err := base64.StdEncoding.DecodeString(s)
	if err != nil {
		return errors.Wrap(err, "error decoding ssh public key")
	}
	pub, err := ssh.ParsePublicKey(data)
	if err != nil {
		return errors.Wrap(err, "error parsing ssh public key")
	}
	p.PublicKey = pub
	return nil
}
type Template = templates.Output
type SSHConfigRequest struct {
	Type string            `json:"type"`
	Data map[string]string `json:"data"`
}
func (r *SSHConfigRequest) Validate() error {
	switch r.Type {
	case "":
		r.Type = provisioner.SSHUserCert
		return nil
	case provisioner.SSHUserCert, provisioner.SSHHostCert:
		return nil
	default:
		return errors.Errorf("unsupported type %s", r.Type)
	}
}
type SSHConfigResponse struct {
	UserTemplates []Template `json:"userTemplates,omitempty"`
	HostTemplates []Template `json:"hostTemplates,omitempty"`
}
type SSHCheckPrincipalRequest struct {
	Type      string `json:"type"`
	Principal string `json:"principal"`
	Token     string `json:"token,omitempty"`
}