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/18baa6a627bdb263c743b358b26daf54 to your computer and use it in GitHub Desktop.
Save blacknon/18baa6a627bdb263c743b358b26daf54 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/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
}
// 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(label string) (pin string, err error) {
pin, err = getPassphrase(label + "'s 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)
}
var slotid int
// var lb string
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)
session.Close()
continue
}
// get public key
pub := []*pkcs11.Attribute{
pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY),
}
keyids := map[int][]byte{}
fmt.Println("----- Get Public Key -----")
obj, _ := session.FindObjects(pub)
for n, o := range obj {
// get label
l, err := o.Label()
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
b, _ := o.Attribute(pkcs11.CKA_ID)
fmt.Println(b)
keyids[n] = b
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)
// lb, _ = o.Label()
}
// set slot id
slotid = int(slot.ID())
fmt.Println(slotid)
pin, err := getPIN(tokenInfo.Label)
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
err = session.Login(pin)
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
fmt.Println("----- Get Private Key -----")
for _, i := range keyids {
priv := []*pkcs11.Attribute{
pkcs11.NewAttribute(pkcs11.CKA_ID, i),
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_OBJECT_ID),
}
obj, err = session.FindObjects(priv)
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
for _, o := range obj {
fmt.Println(o.Label)
piv := p11.PrivateKey(o)
// signer, err := ssh.NewSignerFromSigner(piv)
// if err != nil {
// fmt.Fprintln(os.Stderr, err)
// continue
// }
// fmt.Println(signer)
fmt.Println(piv)
b, err := o.Attribute(pkcs11.CKA_ID)
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
fmt.Println("ok")
fmt.Println(b)
}
}
fmt.Println("----- check loop -----")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment