Skip to content

Instantly share code, notes, and snippets.

@blacknon
Last active January 30, 2023 02:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save blacknon/3b4cab6502ba1786fc2821f920a038c9 to your computer and use it in GitHub Desktop.
Save blacknon/3b4cab6502ba1786fc2821f920a038c9 to your computer and use it in GitHub Desktop.
goで`github.com/miekg/pkcs11/p11`を使って、Yubikey内からsshのCryptoSignerを取得するサンプルコード
// Copyright (c) 2020 Blacknon. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
// `github.com/miekg/pkcs11/p11`を使って、Yubikey内からsshのCryptoSignerを取得するサンプルコード
package main
import (
"crypto"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"fmt"
"log"
"os"
"github.com/ThalesIgnite/crypto11"
"github.com/miekg/pkcs11"
"github.com/miekg/pkcs11/p11"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/terminal"
)
var (
provider = "/usr/local/lib/opensc-pkcs11.so"
)
// C11 struct
type C11 struct {
Provider string
PIN string
SlotID *int
// Context is crypto11 Context
Context *crypto11.Context
}
// CreateContext is create and set C11.Context
func (c *C11) CreateContext() (err error) {
config := &crypto11.Config{
Path: c.Provider,
SlotNumber: c.SlotID,
Pin: c.PIN,
}
// set c.Context
c.Context, err = crypto11.Configure(config)
return
}
// GetSigner is return crypto11.Signer and error
func (c *C11) GetSigner() (signers []crypto.Signer, err error) {
c11signers, err := c.Context.FindAllKeyPairs()
if err != nil {
return
}
for _, sig := range c11signers {
signers = append(signers, sig.(crypto.Signer))
}
return
}
// ------
// getPassphrase gets the passphrase from virtual terminal input and returns the result. Works only on UNIX-based OS.
func getPassphrase(msg string) (input string, err error) {
fmt.Fprintf(os.Stderr, msg)
// Open /dev/tty
tty, err := os.Open("/dev/tty")
if err != nil {
log.Fatal(err)
}
defer tty.Close()
// get input
result, err := terminal.ReadPassword(int(tty.Fd()))
if len(result) == 0 {
err = fmt.Errorf("err: input is empty")
return
}
input = string(result)
fmt.Println()
return
}
func getPIN() (pin string, err error) {
pin, err = getPassphrase("PKCS11 PIN:")
return
}
func main() {
module, err := p11.OpenModule(provider)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
slots, err := module.Slots()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
for _, slot := range slots {
tokenInfo, err := slot.TokenInfo()
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
fmt.Println(tokenInfo.Label)
session, err := slot.OpenSession()
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
// get public key
pub := []*pkcs11.Attribute{
pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY),
}
obj, _ := session.FindObjects(pub)
for _, o := range obj {
// get label
l, err := o.Label()
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
v, err := o.Value()
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
rsaPubKey, err := x509.ParsePKIXPublicKey(v)
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
sshKey, ok := rsaPubKey.(*rsa.PublicKey)
if !ok {
fmt.Fprintln(os.Stderr, "invalid PEM passed in from user")
continue
}
pub, err := ssh.NewPublicKey(sshKey)
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
p := base64.StdEncoding.EncodeToString(pub.Marshal())
fmt.Println(l, ":", p)
}
// // login
pin, err := getPIN()
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
// // get signer
// err = session.Login(pin)
// if err != nil {
// fmt.Fprintln(os.Stderr, err)
// continue
// }
// priv := []*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),
// // pkcs11.NewAttribute(pkcs11.CKA_LABEL, label),
// }
// obj, err = session.FindObjects(priv)
// if err != nil {
// fmt.Fprintln(os.Stderr, err)
// continue
// }
// for _, o := range obj {
// fmt.Println(o.Label)
// priv := p11.KeyPair(o.)
// sig := priv.(crypto.Signer)
// }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment