// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ssh

import (
	
	
	
	
	
	
	
)

// Certificate algorithm names from [PROTOCOL.certkeys]. These values can appear
// in Certificate.Type, PublicKey.Type, and ClientConfig.HostKeyAlgorithms.
// Unlike key algorithm names, these are not passed to AlgorithmSigner nor
// returned by MultiAlgorithmSigner and don't appear in the Signature.Format
// field.
const (
	CertAlgoRSAv01        = "ssh-rsa-cert-v01@openssh.com"
	CertAlgoDSAv01        = "ssh-dss-cert-v01@openssh.com"
	CertAlgoECDSA256v01   = "ecdsa-sha2-nistp256-cert-v01@openssh.com"
	CertAlgoECDSA384v01   = "ecdsa-sha2-nistp384-cert-v01@openssh.com"
	CertAlgoECDSA521v01   = "ecdsa-sha2-nistp521-cert-v01@openssh.com"
	CertAlgoSKECDSA256v01 = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"
	CertAlgoED25519v01    = "ssh-ed25519-cert-v01@openssh.com"
	CertAlgoSKED25519v01  = "sk-ssh-ed25519-cert-v01@openssh.com"

	// CertAlgoRSASHA256v01 and CertAlgoRSASHA512v01 can't appear as a
	// Certificate.Type (or PublicKey.Type), but only in
	// ClientConfig.HostKeyAlgorithms.
	CertAlgoRSASHA256v01 = "rsa-sha2-256-cert-v01@openssh.com"
	CertAlgoRSASHA512v01 = "rsa-sha2-512-cert-v01@openssh.com"
)

const (
	// Deprecated: use CertAlgoRSAv01.
	CertSigAlgoRSAv01 = CertAlgoRSAv01
	// Deprecated: use CertAlgoRSASHA256v01.
	CertSigAlgoRSASHA2256v01 = CertAlgoRSASHA256v01
	// Deprecated: use CertAlgoRSASHA512v01.
	CertSigAlgoRSASHA2512v01 = CertAlgoRSASHA512v01
)

// Certificate types distinguish between host and user
// certificates. The values can be set in the CertType field of
// Certificate.
const (
	UserCert = 1
	HostCert = 2
)

// Signature represents a cryptographic signature.
type Signature struct {
	Format string
	Blob   []byte
	Rest   []byte `ssh:"rest"`
}

// CertTimeInfinity can be used for OpenSSHCertV01.ValidBefore to indicate that
// a certificate does not expire.
const CertTimeInfinity = 1<<64 - 1

// An Certificate represents an OpenSSH certificate as defined in
// [PROTOCOL.certkeys]?rev=1.8. The Certificate type implements the
// PublicKey interface, so it can be unmarshaled using
// ParsePublicKey.
type Certificate struct {
	Nonce           []byte
	Key             PublicKey
	Serial          uint64
	CertType        uint32
	KeyId           string
	ValidPrincipals []string
	ValidAfter      uint64
	ValidBefore     uint64
	Permissions
	Reserved     []byte
	SignatureKey PublicKey
	Signature    *Signature
}

// genericCertData holds the key-independent part of the certificate data.
// Overall, certificates contain an nonce, public key fields and
// key-independent fields.
type genericCertData struct {
	Serial          uint64
	CertType        uint32
	KeyId           string
	ValidPrincipals []byte
	ValidAfter      uint64
	ValidBefore     uint64
	CriticalOptions []byte
	Extensions      []byte
	Reserved        []byte
	SignatureKey    []byte
	Signature       []byte
}

func marshalStringList( []string) []byte {
	var  []byte
	for ,  := range  {
		 := struct{  string }{}
		 = append(, Marshal(&)...)
	}
	return 
}

type optionsTuple struct {
	Key   string
	Value []byte
}

type optionsTupleValue struct {
	Value string
}

// serialize a map of critical options or extensions
// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,
// we need two length prefixes for a non-empty string value
func marshalTuples( map[string]string) []byte {
	 := make([]string, 0, len())
	for  := range  {
		 = append(, )
	}
	sort.Strings()

	var  []byte
	for ,  := range  {
		 := optionsTuple{Key: }
		if  := []; len() > 0 {
			.Value = Marshal(&optionsTupleValue{})
		}
		 = append(, Marshal(&)...)
	}
	return 
}

// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,
// we need two length prefixes for a non-empty option value
func parseTuples( []byte) (map[string]string, error) {
	 := map[string]string{}
	var  string
	var  bool

	for len() > 0 {
		var , ,  []byte
		var  bool

		if , ,  = parseString(); ! {
			return nil, errShortRead
		}
		 := string()
		// according to [PROTOCOL.certkeys], the names must be in
		// lexical order.
		if  &&  <=  {
			return nil, fmt.Errorf("ssh: certificate options are not in lexical order")
		}
		,  = , true
		// the next field is a data field, which if non-empty has a string embedded
		if , ,  = parseString(); ! {
			return nil, errShortRead
		}
		if len() > 0 {
			, ,  = parseString()
			if ! {
				return nil, errShortRead
			}
			if len() > 0 {
				return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value")
			}
			[] = string()
		} else {
			[] = ""
		}
	}
	return , nil
}

func parseCert( []byte,  string) (*Certificate, error) {
	, ,  := parseString()
	if ! {
		return nil, errShortRead
	}

	, ,  := parsePubKey(, )
	if  != nil {
		return nil, 
	}

	var  genericCertData
	if  := Unmarshal(, &);  != nil {
		return nil, 
	}

	 := &Certificate{
		Nonce:       ,
		Key:         ,
		Serial:      .Serial,
		CertType:    .CertType,
		KeyId:       .KeyId,
		ValidAfter:  .ValidAfter,
		ValidBefore: .ValidBefore,
	}

	for  := .ValidPrincipals; len() > 0; {
		, ,  := parseString()
		if ! {
			return nil, errShortRead
		}
		.ValidPrincipals = append(.ValidPrincipals, string())
		 = 
	}

	.CriticalOptions,  = parseTuples(.CriticalOptions)
	if  != nil {
		return nil, 
	}
	.Extensions,  = parseTuples(.Extensions)
	if  != nil {
		return nil, 
	}
	.Reserved = .Reserved
	,  := ParsePublicKey(.SignatureKey)
	if  != nil {
		return nil, 
	}

	.SignatureKey = 
	.Signature, ,  = parseSignatureBody(.Signature)
	if ! || len() > 0 {
		return nil, errors.New("ssh: signature parse error")
	}

	return , nil
}

type openSSHCertSigner struct {
	pub    *Certificate
	signer Signer
}

type algorithmOpenSSHCertSigner struct {
	*openSSHCertSigner
	algorithmSigner AlgorithmSigner
}

// NewCertSigner returns a Signer that signs with the given Certificate, whose
// private key is held by signer. It returns an error if the public key in cert
// doesn't match the key used by signer.
func ( *Certificate,  Signer) (Signer, error) {
	if !bytes.Equal(.Key.Marshal(), .PublicKey().Marshal()) {
		return nil, errors.New("ssh: signer and cert have different public key")
	}

	switch s := .(type) {
	case MultiAlgorithmSigner:
		return &multiAlgorithmSigner{
			AlgorithmSigner: &algorithmOpenSSHCertSigner{
				&openSSHCertSigner{, }, },
			supportedAlgorithms: .Algorithms(),
		}, nil
	case AlgorithmSigner:
		return &algorithmOpenSSHCertSigner{
			&openSSHCertSigner{, }, }, nil
	default:
		return &openSSHCertSigner{, }, nil
	}
}

func ( *openSSHCertSigner) ( io.Reader,  []byte) (*Signature, error) {
	return .signer.Sign(, )
}

func ( *openSSHCertSigner) () PublicKey {
	return .pub
}

func ( *algorithmOpenSSHCertSigner) ( io.Reader,  []byte,  string) (*Signature, error) {
	return .algorithmSigner.SignWithAlgorithm(, , )
}

const sourceAddressCriticalOption = "source-address"

// CertChecker does the work of verifying a certificate. Its methods
// can be plugged into ClientConfig.HostKeyCallback and
// ServerConfig.PublicKeyCallback. For the CertChecker to work,
// minimally, the IsAuthority callback should be set.
type CertChecker struct {
	// SupportedCriticalOptions lists the CriticalOptions that the
	// server application layer understands. These are only used
	// for user certificates.
	SupportedCriticalOptions []string

	// IsUserAuthority should return true if the key is recognized as an
	// authority for the given user certificate. This allows for
	// certificates to be signed by other certificates. This must be set
	// if this CertChecker will be checking user certificates.
	IsUserAuthority func(auth PublicKey) bool

	// IsHostAuthority should report whether the key is recognized as
	// an authority for this host. This allows for certificates to be
	// signed by other keys, and for those other keys to only be valid
	// signers for particular hostnames. This must be set if this
	// CertChecker will be checking host certificates.
	IsHostAuthority func(auth PublicKey, address string) bool

	// Clock is used for verifying time stamps. If nil, time.Now
	// is used.
	Clock func() time.Time

	// UserKeyFallback is called when CertChecker.Authenticate encounters a
	// public key that is not a certificate. It must implement validation
	// of user keys or else, if nil, all such keys are rejected.
	UserKeyFallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)

	// HostKeyFallback is called when CertChecker.CheckHostKey encounters a
	// public key that is not a certificate. It must implement host key
	// validation or else, if nil, all such keys are rejected.
	HostKeyFallback HostKeyCallback

	// IsRevoked is called for each certificate so that revocation checking
	// can be implemented. It should return true if the given certificate
	// is revoked and false otherwise. If nil, no certificates are
	// considered to have been revoked.
	IsRevoked func(cert *Certificate) bool
}

// CheckHostKey checks a host key certificate. This method can be
// plugged into ClientConfig.HostKeyCallback.
func ( *CertChecker) ( string,  net.Addr,  PublicKey) error {
	,  := .(*Certificate)
	if ! {
		if .HostKeyFallback != nil {
			return .HostKeyFallback(, , )
		}
		return errors.New("ssh: non-certificate host key")
	}
	if .CertType != HostCert {
		return fmt.Errorf("ssh: certificate presented as a host key has type %d", .CertType)
	}
	if !.IsHostAuthority(.SignatureKey, ) {
		return fmt.Errorf("ssh: no authorities for hostname: %v", )
	}

	, ,  := net.SplitHostPort()
	if  != nil {
		return 
	}

	// Pass hostname only as principal for host certificates (consistent with OpenSSH)
	return .CheckCert(, )
}

// Authenticate checks a user certificate. Authenticate can be used as
// a value for ServerConfig.PublicKeyCallback.
func ( *CertChecker) ( ConnMetadata,  PublicKey) (*Permissions, error) {
	,  := .(*Certificate)
	if ! {
		if .UserKeyFallback != nil {
			return .UserKeyFallback(, )
		}
		return nil, errors.New("ssh: normal key pairs not accepted")
	}

	if .CertType != UserCert {
		return nil, fmt.Errorf("ssh: cert has type %d", .CertType)
	}
	if !.IsUserAuthority(.SignatureKey) {
		return nil, fmt.Errorf("ssh: certificate signed by unrecognized authority")
	}

	if  := .CheckCert(.User(), );  != nil {
		return nil, 
	}

	return &.Permissions, nil
}

// CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and
// the signature of the certificate.
func ( *CertChecker) ( string,  *Certificate) error {
	if .IsRevoked != nil && .IsRevoked() {
		return fmt.Errorf("ssh: certificate serial %d revoked", .Serial)
	}

	for  := range .CriticalOptions {
		// sourceAddressCriticalOption will be enforced by
		// serverAuthenticate
		if  == sourceAddressCriticalOption {
			continue
		}

		 := false
		for ,  := range .SupportedCriticalOptions {
			if  ==  {
				 = true
				break
			}
		}
		if ! {
			return fmt.Errorf("ssh: unsupported critical option %q in certificate", )
		}
	}

	if len(.ValidPrincipals) > 0 {
		// By default, certs are valid for all users/hosts.
		 := false
		for ,  := range .ValidPrincipals {
			if  ==  {
				 = true
				break
			}
		}
		if ! {
			return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", , .ValidPrincipals)
		}
	}

	 := .Clock
	if  == nil {
		 = time.Now
	}

	 := ().Unix()
	if  := int64(.ValidAfter);  < 0 ||  < int64(.ValidAfter) {
		return fmt.Errorf("ssh: cert is not yet valid")
	}
	if  := int64(.ValidBefore); .ValidBefore != uint64(CertTimeInfinity) && ( >=  ||  < 0) {
		return fmt.Errorf("ssh: cert has expired")
	}
	if  := .SignatureKey.Verify(.bytesForSigning(), .Signature);  != nil {
		return fmt.Errorf("ssh: certificate signature does not verify")
	}

	return nil
}

// SignCert signs the certificate with an authority, setting the Nonce,
// SignatureKey, and Signature fields. If the authority implements the
// MultiAlgorithmSigner interface the first algorithm in the list is used. This
// is useful if you want to sign with a specific algorithm.
func ( *Certificate) ( io.Reader,  Signer) error {
	.Nonce = make([]byte, 32)
	if ,  := io.ReadFull(, .Nonce);  != nil {
		return 
	}
	.SignatureKey = .PublicKey()

	if ,  := .(MultiAlgorithmSigner);  {
		if len(.Algorithms()) == 0 {
			return errors.New("the provided authority has no signature algorithm")
		}
		// Use the first algorithm in the list.
		,  := .SignWithAlgorithm(, .bytesForSigning(), .Algorithms()[0])
		if  != nil {
			return 
		}
		.Signature = 
		return nil
	} else if ,  := .(AlgorithmSigner);  && .PublicKey().Type() == KeyAlgoRSA {
		// Default to KeyAlgoRSASHA512 for ssh-rsa signers.
		// TODO: consider using KeyAlgoRSASHA256 as default.
		,  := .SignWithAlgorithm(, .bytesForSigning(), KeyAlgoRSASHA512)
		if  != nil {
			return 
		}
		.Signature = 
		return nil
	}

	,  := .Sign(, .bytesForSigning())
	if  != nil {
		return 
	}
	.Signature = 
	return nil
}

// certKeyAlgoNames is a mapping from known certificate algorithm names to the
// corresponding public key signature algorithm.
//
// This map must be kept in sync with the one in agent/client.go.
var certKeyAlgoNames = map[string]string{
	CertAlgoRSAv01:        KeyAlgoRSA,
	CertAlgoRSASHA256v01:  KeyAlgoRSASHA256,
	CertAlgoRSASHA512v01:  KeyAlgoRSASHA512,
	CertAlgoDSAv01:        KeyAlgoDSA,
	CertAlgoECDSA256v01:   KeyAlgoECDSA256,
	CertAlgoECDSA384v01:   KeyAlgoECDSA384,
	CertAlgoECDSA521v01:   KeyAlgoECDSA521,
	CertAlgoSKECDSA256v01: KeyAlgoSKECDSA256,
	CertAlgoED25519v01:    KeyAlgoED25519,
	CertAlgoSKED25519v01:  KeyAlgoSKED25519,
}

// underlyingAlgo returns the signature algorithm associated with algo (which is
// an advertised or negotiated public key or host key algorithm). These are
// usually the same, except for certificate algorithms.
func underlyingAlgo( string) string {
	if ,  := certKeyAlgoNames[];  {
		return 
	}
	return 
}

// certificateAlgo returns the certificate algorithms that uses the provided
// underlying signature algorithm.
func certificateAlgo( string) ( string,  bool) {
	for ,  := range certKeyAlgoNames {
		if  ==  {
			return , true
		}
	}
	return "", false
}

func ( *Certificate) () []byte {
	 := *
	.Signature = nil
	 := .Marshal()
	// Drop trailing signature length.
	return [:len()-4]
}

// Marshal serializes c into OpenSSH's wire format. It is part of the
// PublicKey interface.
func ( *Certificate) () []byte {
	 := genericCertData{
		Serial:          .Serial,
		CertType:        .CertType,
		KeyId:           .KeyId,
		ValidPrincipals: marshalStringList(.ValidPrincipals),
		ValidAfter:      uint64(.ValidAfter),
		ValidBefore:     uint64(.ValidBefore),
		CriticalOptions: marshalTuples(.CriticalOptions),
		Extensions:      marshalTuples(.Extensions),
		Reserved:        .Reserved,
		SignatureKey:    .SignatureKey.Marshal(),
	}
	if .Signature != nil {
		.Signature = Marshal(.Signature)
	}
	 := Marshal(&)
	 := .Key.Marshal()
	_, , _ = parseString()
	 := Marshal(&struct {
		  string
		 []byte
		   []byte `ssh:"rest"`
	}{.Type(), .Nonce, })

	 := make([]byte, 0, len()+len())
	 = append(, ...)
	 = append(, ...)
	return 
}

// Type returns the certificate algorithm name. It is part of the PublicKey interface.
func ( *Certificate) () string {
	,  := certificateAlgo(.Key.Type())
	if ! {
		panic("unknown certificate type for key type " + .Key.Type())
	}
	return 
}

// Verify verifies a signature against the certificate's public
// key. It is part of the PublicKey interface.
func ( *Certificate) ( []byte,  *Signature) error {
	return .Key.Verify(, )
}

func parseSignatureBody( []byte) ( *Signature,  []byte,  bool) {
	, ,  := parseString()
	if ! {
		return
	}

	 = &Signature{
		Format: string(),
	}

	if .Blob, ,  = parseString(); ! {
		return
	}

	switch .Format {
	case KeyAlgoSKECDSA256, CertAlgoSKECDSA256v01, KeyAlgoSKED25519, CertAlgoSKED25519v01:
		.Rest = 
		return , nil, 
	}

	return , , 
}

func parseSignature( []byte) ( *Signature,  []byte,  bool) {
	, ,  := parseString()
	if ! {
		return
	}

	, ,  := parseSignatureBody()
	if ! || len() > 0 {
		return nil, nil, false
	}
	return
}