Source File
client.go
Belonging Package
golang.org/x/crypto/ssh/agent
package agent // import "golang.org/x/crypto/ssh/agent"
import (
)
type SignatureFlags uint32
const (
SignatureFlagReserved SignatureFlags = 1 << iota
SignatureFlagRsaSha256
SignatureFlagRsaSha512
)
RemoveAll() error
Signers() ([]ssh.Signer, error)
}
type ExtendedAgent interface {
Agent
ExtensionDetails []byte
}
const (
agentRequestV1Identities = 1
agentRemoveAllV1Identities = 9
agentAddIdentity = 17
agentRemoveIdentity = 18
agentRemoveAllIdentities = 19
agentAddIDConstrained = 25
agentAddSmartcardKey = 20
agentRemoveSmartcardKey = 21
agentLock = 22
agentUnlock = 23
agentAddSmartcardKeyConstrained = 26
const maxAgentResponseBytes = 16 << 20
const agentFailure = 5
type failureAgentMsg struct{}
const agentSuccess = 6
type successAgentMsg struct{}
const agentRequestIdentities = 11
type requestIdentitiesAgentMsg struct{}
const agentIdentitiesAnswer = 12
type identitiesAnswerAgentMsg struct {
NumKeys uint32 `sshtype:"12"`
Keys []byte `ssh:"rest"`
}
const agentSignRequest = 13
type signRequestAgentMsg struct {
KeyBlob []byte `sshtype:"13"`
Data []byte
Flags uint32
}
const agentSignResponse = 14
type signResponseAgentMsg struct {
SigBlob []byte `sshtype:"14"`
}
type publicKey struct {
Format string
Rest []byte `ssh:"rest"`
}
type constrainLifetimeAgentMsg struct {
LifetimeSecs uint32 `sshtype:"1"`
}
type constrainExtensionAgentMsg struct {
ExtensionName string `sshtype:"3"`
ExtensionDetails []byte
const agentExtension = 27
const agentExtensionFailure = 28
var ErrExtensionUnsupported = errors.New("agent: extension unsupported")
type extensionAgentMsg struct {
ExtensionType string `sshtype:"27"`
Contents []byte
}
func ( *Key) () string {
:= string(.Format) + " " + base64.StdEncoding.EncodeToString(.Blob)
if .Comment != "" {
+= " " + .Comment
}
return
}
func ( *Key) ( []byte, *ssh.Signature) error {
, := ssh.ParsePublicKey(.Blob)
if != nil {
return fmt.Errorf("agent: bad public key: %v", )
}
return .Verify(, )
}
type wireKey struct {
Format string
Rest []byte `ssh:"rest"`
}
func ( []byte) ( *Key, []byte, error) {
var struct {
[]byte
string
[]byte `ssh:"rest"`
}
if := ssh.Unmarshal(, &); != nil {
return nil, nil,
}
var wireKey
if := ssh.Unmarshal(., &); != nil {
return nil, nil,
}
return &Key{
Format: .Format,
Blob: .,
Comment: .,
}, ., nil
}
func ( io.ReadWriter) ExtendedAgent {
return &client{conn: }
}
func ( *client) ( []byte) ( []byte, error) {
.mu.Lock()
defer .mu.Unlock()
:= make([]byte, 4+len())
binary.BigEndian.PutUint32(, uint32(len()))
copy([4:], )
if _, = .conn.Write(); != nil {
return nil, clientErr()
}
var [4]byte
if _, = io.ReadFull(.conn, [:]); != nil {
return nil, clientErr()
}
:= binary.BigEndian.Uint32([:])
if > maxAgentResponseBytes {
return nil, clientErr(errors.New("response too large"))
}
:= make([]byte, )
if _, = io.ReadFull(.conn, ); != nil {
return nil, clientErr()
}
return , nil
}
func ( *client) ( []byte) error {
, := .call()
if != nil {
return
}
if , := .(*successAgentMsg); {
return nil
}
return errors.New("agent: failure")
}
func ( *client) () error {
return .simpleCall([]byte{agentRemoveAllIdentities})
}
func ( *client) ( ssh.PublicKey) error {
:= ssh.Marshal(&agentRemoveIdentityMsg{
KeyBlob: .Marshal(),
})
return .simpleCall()
}
func ( *client) ( []byte) error {
:= ssh.Marshal(&agentLockMsg{
Passphrase: ,
})
return .simpleCall()
}
func ( *client) ( []byte) error {
:= ssh.Marshal(&agentUnlockMsg{
Passphrase: ,
})
return .simpleCall()
}
:= []byte{agentRequestIdentities}
, := .call()
if != nil {
return nil,
}
switch msg := .(type) {
case *identitiesAnswerAgentMsg:
if .NumKeys > maxAgentResponseBytes/8 {
return nil, errors.New("agent: too many keys in agent reply")
}
:= make([]*Key, .NumKeys)
:= .Keys
for := uint32(0); < .NumKeys; ++ {
var *Key
var error
if , , = parseKey(); != nil {
return nil,
}
[] =
}
return , nil
case *failureAgentMsg:
return nil, errors.New("agent: failed to list keys")
}
panic("unreachable")
}
func ( *client) ( ssh.PublicKey, []byte) (*ssh.Signature, error) {
return .SignWithFlags(, , 0)
}
func ( *client) ( ssh.PublicKey, []byte, SignatureFlags) (*ssh.Signature, error) {
:= ssh.Marshal(signRequestAgentMsg{
KeyBlob: .Marshal(),
Data: ,
Flags: uint32(),
})
, := .call()
if != nil {
return nil,
}
switch msg := .(type) {
case *signResponseAgentMsg:
var ssh.Signature
if := ssh.Unmarshal(.SigBlob, &); != nil {
return nil,
}
return &, nil
case *failureAgentMsg:
return nil, errors.New("agent: failed to sign challenge")
}
panic("unreachable")
}
func ( []byte) (interface{}, error) {
if len() < 1 {
return nil, errors.New("agent: empty packet")
}
var interface{}
switch [0] {
case agentFailure:
return new(failureAgentMsg), nil
case agentSuccess:
return new(successAgentMsg), nil
case agentIdentitiesAnswer:
= new(identitiesAnswerAgentMsg)
case agentSignResponse:
= new(signResponseAgentMsg)
case agentV1IdentitiesAnswer:
= new(agentV1IdentityMsg)
default:
return nil, fmt.Errorf("agent: unknown type tag %d", [0])
}
if := ssh.Unmarshal(, ); != nil {
return nil,
}
return , nil
}
type rsaKeyMsg struct {
Type string `sshtype:"17|25"`
N *big.Int
E *big.Int
D *big.Int
Iqmp *big.Int // IQMP = Inverse Q Mod P
P *big.Int
Q *big.Int
Comments string
Constraints []byte `ssh:"rest"`
}
type dsaKeyMsg struct {
Type string `sshtype:"17|25"`
P *big.Int
Q *big.Int
G *big.Int
Y *big.Int
X *big.Int
Comments string
Constraints []byte `ssh:"rest"`
}
type ecdsaKeyMsg struct {
Type string `sshtype:"17|25"`
Curve string
KeyBytes []byte
D *big.Int
Comments string
Constraints []byte `ssh:"rest"`
}
type ed25519KeyMsg struct {
Type string `sshtype:"17|25"`
Pub []byte
Priv []byte
Comments string
Constraints []byte `ssh:"rest"`
}
func ( *client) ( interface{}, string, []byte) error {
var []byte
switch k := .(type) {
case *rsa.PrivateKey:
if len(.Primes) != 2 {
return fmt.Errorf("agent: unsupported RSA key with %d primes", len(.Primes))
}
.Precompute()
= ssh.Marshal(rsaKeyMsg{
Type: ssh.KeyAlgoRSA,
N: .N,
E: big.NewInt(int64(.E)),
D: .D,
Iqmp: .Precomputed.Qinv,
P: .Primes[0],
Q: .Primes[1],
Comments: ,
Constraints: ,
})
case *dsa.PrivateKey:
= ssh.Marshal(dsaKeyMsg{
Type: ssh.KeyAlgoDSA,
P: .P,
Q: .Q,
G: .G,
Y: .Y,
X: .X,
Comments: ,
Constraints: ,
})
case *ecdsa.PrivateKey:
:= fmt.Sprintf("nistp%d", .Params().BitSize)
= ssh.Marshal(ecdsaKeyMsg{
Type: "ecdsa-sha2-" + ,
Curve: ,
KeyBytes: elliptic.Marshal(.Curve, .X, .Y),
D: .D,
Comments: ,
Constraints: ,
})
case ed25519.PrivateKey:
= ssh.Marshal(ed25519KeyMsg{
Type: ssh.KeyAlgoED25519,
Pub: []byte()[32:],
Priv: []byte(),
Comments: ,
Constraints: ,
case *ed25519.PrivateKey:
= ssh.Marshal(ed25519KeyMsg{
Type: ssh.KeyAlgoED25519,
Pub: []byte(*)[32:],
Priv: []byte(*),
Comments: ,
Constraints: ,
})
default:
return fmt.Errorf("agent: unsupported key type %T", )
}
if len() != 0 {
[0] = agentAddIDConstrained
}
, := .call()
if != nil {
return
}
if , := .(*successAgentMsg); {
return nil
}
return errors.New("agent: failure")
}
type rsaCertMsg struct {
Type string `sshtype:"17|25"`
CertBytes []byte
D *big.Int
Iqmp *big.Int // IQMP = Inverse Q Mod P
P *big.Int
Q *big.Int
Comments string
Constraints []byte `ssh:"rest"`
}
type dsaCertMsg struct {
Type string `sshtype:"17|25"`
CertBytes []byte
X *big.Int
Comments string
Constraints []byte `ssh:"rest"`
}
type ecdsaCertMsg struct {
Type string `sshtype:"17|25"`
CertBytes []byte
D *big.Int
Comments string
Constraints []byte `ssh:"rest"`
}
type ed25519CertMsg struct {
Type string `sshtype:"17|25"`
CertBytes []byte
Pub []byte
Priv []byte
Comments string
Constraints []byte `ssh:"rest"`
}
func ( *client) ( AddedKey) error {
var []byte
if := .LifetimeSecs; != 0 {
= append(, ssh.Marshal(constrainLifetimeAgentMsg{})...)
}
if .ConfirmBeforeUse {
= append(, agentConstrainConfirm)
}
:= .Certificate
if == nil {
return .insertKey(.PrivateKey, .Comment, )
}
return .insertCert(.PrivateKey, , .Comment, )
}
func ( *client) ( interface{}, *ssh.Certificate, string, []byte) error {
var []byte
switch k := .(type) {
case *rsa.PrivateKey:
if len(.Primes) != 2 {
return fmt.Errorf("agent: unsupported RSA key with %d primes", len(.Primes))
}
.Precompute()
= ssh.Marshal(rsaCertMsg{
Type: .Type(),
CertBytes: .Marshal(),
D: .D,
Iqmp: .Precomputed.Qinv,
P: .Primes[0],
Q: .Primes[1],
Comments: ,
Constraints: ,
})
case *dsa.PrivateKey:
= ssh.Marshal(dsaCertMsg{
Type: .Type(),
CertBytes: .Marshal(),
X: .X,
Comments: ,
Constraints: ,
})
case *ecdsa.PrivateKey:
= ssh.Marshal(ecdsaCertMsg{
Type: .Type(),
CertBytes: .Marshal(),
D: .D,
Comments: ,
Constraints: ,
})
case ed25519.PrivateKey:
= ssh.Marshal(ed25519CertMsg{
Type: .Type(),
CertBytes: .Marshal(),
Pub: []byte()[32:],
Priv: []byte(),
Comments: ,
Constraints: ,
if len() != 0 {
[0] = agentAddIDConstrained
}
, := ssh.NewSignerFromKey()
if != nil {
return
}
if bytes.Compare(.Key.Marshal(), .PublicKey().Marshal()) != 0 {
return errors.New("agent: signer and cert have different public key")
}
, := .call()
if != nil {
return
}
if , := .(*successAgentMsg); {
return nil
}
return errors.New("agent: failure")
}
return .agent.Sign(.pub, )
}
func ( *agentKeyringSigner) ( io.Reader, []byte, crypto.SignerOpts) (*ssh.Signature, error) {
var SignatureFlags
if != nil {
switch .HashFunc() {
case crypto.SHA256:
= SignatureFlagRsaSha256
case crypto.SHA512:
= SignatureFlagRsaSha512
}
}
return .agent.SignWithFlags(.pub, , )
}
if [0] == agentFailure {
return nil, ErrExtensionUnsupported
}
if [0] == agentExtensionFailure {
return nil, errors.New("agent: generic extension failure")
}
return , nil
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |