-
-
Save csobankesmarki/c2ed4f7f5782c2b27985e4401989984b to your computer and use it in GitHub Desktop.
ssh_term_pkcs11_2.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"crypto" | |
"fmt" | |
"os" | |
"os/signal" | |
"syscall" | |
"github.com/ThalesIgnite/crypto11" | |
"github.com/miekg/pkcs11" | |
"golang.org/x/crypto/ssh" | |
"golang.org/x/crypto/ssh/terminal" | |
) | |
where ( | |
pkcs11Provider = "/usr/local/lib/opensc-pkcs11.so" | |
addr = "target.host" | |
port = "22" | |
user = "user" | |
) | |
type P11 struct { | |
Ctx *pkcs11.Ctx | |
Label string | |
SlotID uint | |
KeyID map [int] [] byte // Is this okay ...? | |
PIN string | |
SessionHandle pkcs11.SessionHandle | |
Signers []ssh.Signer | |
} | |
// Create ctx (main object of pkcs11) | |
func (p *P11) CreateCtx() (err error) { | |
ctx := pkcs11.New(pkcs11Provider) | |
err = ctx.Initialize() | |
if err != nil { | |
return | |
} | |
p.Ctx = ctx | |
return | |
} | |
// Get hardware token information via PKCS11 | |
func (p *P11) GetTokenLabel() (err error) { | |
slots, err := p.Ctx.GetSlotList(false) | |
if err != nil { | |
return | |
} | |
if len(slots) > 1 { | |
err = fmt.Errorf("err: %s", "Single token only") | |
return | |
} | |
if len(slots) == 0 { | |
err = fmt.Errorf("err: %s", "No token") | |
return | |
} | |
slotID := slots[0] | |
tokenInfo, err := p.Ctx.GetTokenInfo(slotID) | |
if err != nil { | |
return | |
} | |
p.SlotID = slotID | |
p.Label = tokenInfo.Label | |
return | |
} | |
// If the struct does not have a PIN, get it | |
func (p *P11) GetPIN() (err error) { | |
if p.PIN == "" { | |
fmt.Printf("PIN: ") | |
pin, err := terminal.ReadPassword(int(syscall.Stdin)) | |
if err != nil { | |
return err | |
} | |
if len(pin) == 0 { | |
err = fmt.Errorf("err: %s", "PIN empty") | |
return err | |
} | |
p.PIN = string(pin) | |
} | |
fmt.Println() | |
return | |
} | |
// Remake Ctx to Crypto11 | |
func (p *P11) RecreateCtx() (err error) { | |
p.Ctx.Destroy() | |
config := &crypto11.PKCS11Config{ | |
Path: pkcs11Provider, | |
TokenLabel: p.Label, | |
Pin: p.PIN, | |
} | |
ctx, err := crypto11.Configure(config) | |
if err != nil { | |
return | |
} | |
session, err := ctx.OpenSession(p.SlotID, pkcs11.CKF_SERIAL_SESSION) | |
if err != nil { | |
return | |
} | |
p.Ctx = ctx | |
p.SessionHandle = session | |
return | |
} | |
// Get the ID of the key file in the token (array because there is a high possibility that there are multiple key files in the token) | |
func (p *P11) GetKeyID() (err error) { | |
// get the ID at the beginning of find templete | |
findTemplate := []*pkcs11.Attribute{ | |
pkcs11.NewAttribute(pkcs11.CKA_ID, true), | |
pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY), | |
pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, true), | |
pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_RSA), | |
} | |
// Find Object | |
p.Ctx.FindObjectsInit(p.SessionHandle, findTemplate) | |
obj, _, err := p.Ctx.FindObjects(p.SessionHandle, 1000) | |
if err != nil { | |
fmt.Println("find obj") | |
return | |
} | |
// Finish searching for Object (Is defer better ??) | |
err = p.Ctx.FindObjectsFinal(p.SessionHandle) | |
p.KeyID = map[int][]byte{} | |
for num, objValue := range obj { | |
attrs, _ := p.Ctx.GetAttributeValue(p.SessionHandle, objValue, findTemplate) | |
p.KeyID[num] = attrs[0].Value | |
} | |
return | |
} | |
func (p *P11) GetSigner() (signers []ssh.Signer, err error) { | |
c11Session := &crypto11.PKCS11Session{p.Ctx, p.SessionHandle} | |
for _, keyID := range p.KeyID { | |
prv, err := crypto11.FindKeyPairOnSession(c11Session, p.SlotID, keyID, nil) | |
if err != nil { | |
return signers, err | |
} | |
// append signer | |
cryptoSigner := prv.(crypto.Signer) | |
sshSigner, _ := ssh.NewSignerFromSigner(cryptoSigner) | |
signers = append(signers, sshSigner) | |
} | |
return signers, err | |
} | |
type Ssh struct { | |
Addr string | |
Port string | |
User string | |
} | |
func (s *Ssh) ConnectTerm(signers []ssh.Signer) (err error) { | |
fmt.Println("Start ConnectTerm") | |
auth := []ssh.AuthMethod{} | |
for _, signer := range signers { | |
auth = append(auth, ssh.PublicKeys(signer)) | |
} | |
sshConfig := &ssh.ClientConfig{ | |
User: s.User, | |
Auth: auth, | |
HostKeyCallback: ssh.InsecureIgnoreHostKey(), | |
BannerCallback: ssh.BannerDisplayStderr(), | |
} | |
// SSH connect. | |
client, err := ssh.Dial("tcp", s.Addr+":"+s.Port, sshConfig) | |
if err != nil { | |
fmt.Printf("ssh connect err: %s\n", err) | |
return | |
} | |
// Create Session | |
session, err := client.NewSession() | |
defer session.Close() | |
// Convert the key input to a format that the connection destination can recognize (this is the key) | |
fd := int(os.Stdin.Fd()) | |
state, err := terminal.MakeRaw(fd) | |
if err != nil { | |
return | |
} | |
defer terminal.Restore(fd, state) | |
// Get terminal size | |
w, h, err := terminal.GetSize(fd) | |
if err != nil { | |
return | |
} | |
modes := ssh.TerminalModes{ | |
ssh.ECHO: 1, | |
ssh.TTY_OP_ISPEED: 14400, | |
ssh.TTY_OP_OSPEED: 14400, | |
} | |
err = session.RequestPty("xterm", h, w, modes) | |
if err != nil { | |
return | |
} | |
session.Stdout = os.Stdout | |
session.Stderr = os.Stderr | |
session.Stdin = os.Stdin | |
err = session.Shell() | |
if err != nil { | |
return | |
} | |
// Terminal size change detection / processing | |
signal_chan := make(chan os.Signal, 1) | |
signal.Notify(signal_chan, syscall.SIGWINCH) | |
go func() { | |
for { | |
s := <-signal_chan | |
switch s { | |
case syscall.SIGWINCH: | |
fd := int(os.Stdout.Fd()) | |
w, h, _ = terminal.GetSize(fd) | |
session.WindowChange(h, w) | |
} | |
} | |
}() | |
err = session.Wait() | |
if err != nil { | |
return | |
} | |
return | |
} | |
func main() { | |
var err error | |
p := new(P11) | |
err = p.CreateCtx() | |
if err != nil { | |
fmt.Println(err) | |
os.Exit (1) | |
} | |
err = p.GetTokenLabel() | |
if err != nil { | |
fmt.Println(err) | |
os.Exit (1) | |
} | |
err = p.GetPIN() | |
if err != nil { | |
fmt.Println(err) | |
os.Exit (1) | |
} | |
err = p.RecreateCtx() | |
if err != nil { | |
fmt.Println("RecreateCtx") | |
fmt.Println(err) | |
os.Exit (1) | |
} | |
err = p.GetKeyID() | |
if err != nil { | |
fmt.Println("GetKeyID") | |
fmt.Println(err) | |
os.Exit (1) | |
} | |
signers, err := p.GetSigner() | |
if err != nil { | |
fmt.Println(err) | |
os.Exit (1) | |
} | |
// ssh connect | |
s := new(Ssh) | |
s.Addr = addr | |
s.Port = port | |
s.User = user | |
err = s.ConnectTerm(signers) | |
if err != nil { | |
fmt.Println(err) | |
os.Exit (1) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment