Select Git revision
-
ale authored
For some reason, even though the default values for RK and UV should be 'false', passing the MakeCredentialOptions causes a failure with YubiKeys >= 5 ("failed to make credential: unsupported option"), so let's just avoid touching the default credential options.
ale authoredFor some reason, even though the default values for RK and UV should be 'false', passing the MakeCredentialOptions causes a failure with YubiKeys >= 5 ("failed to make credential: unsupported option"), so let's just avoid touching the default credential options.
main.go 2.31 KiB
package main
import (
"encoding/base64"
"errors"
"flag"
"fmt"
"log"
"os"
"github.com/duo-labs/webauthn/protocol/webauthncose"
"github.com/fxamacker/cbor/v2"
"github.com/keys-pub/go-libfido2"
"golang.org/x/term"
)
var (
forceDevicePath = flag.String("device", "", "force usage of a specific HID device (default: autodetect)")
username = flag.String("username", os.Getenv("USER"), "username")
rpID = flag.String("rpid", "", "WebAuthN relying party identifier")
)
func readPIN() (string, error) {
fmt.Printf("\rPIN> ")
pw, err := term.ReadPassword(int(os.Stdin.Fd()))
fmt.Printf("\n")
return string(pw), err
}
func fido2ToCOSE(pk []byte) []byte {
var parsed webauthncose.EC2PublicKeyData
parsed.KeyType = int64(webauthncose.EllipticKey)
parsed.Algorithm = int64(webauthncose.AlgES256)
parsed.Curve = 0
parsed.XCoord = pk[:32]
parsed.YCoord = pk[32:]
data, _ := cbor.Marshal(&parsed)
return data
}
func main() {
log.SetFlags(0)
flag.Parse()
if *rpID == "" {
log.Fatal("must specify --rpid")
}
devicePath := *forceDevicePath
if devicePath == "" {
locs, err := libfido2.DeviceLocations()
if err != nil {
log.Fatal("error enumerating devices: %v", err)
}
if len(locs) == 0 {
log.Fatal("error: no FIDO2 devices found")
}
log.Printf("using %s %s", locs[0].Manufacturer, locs[0].Product)
devicePath = locs[0].Path
}
device, err := libfido2.NewDevice(devicePath)
if err != nil {
log.Fatal("error opening device: %v", err)
}
// Generate pseudorandom challenge and user ID.
challenge := libfido2.RandBytes(32)
userID := libfido2.RandBytes(32)
fmt.Println("touch the device (you may be asked for a pin first)......")
var pin string
var attest *libfido2.Attestation
for {
attest, err = device.MakeCredential(
challenge,
libfido2.RelyingParty{
ID: *rpID,
Name: *rpID,
},
libfido2.User{
ID: userID,
Name: *username,
},
libfido2.ES256,
pin,
nil,
)
if errors.Is(err, libfido2.ErrPinRequired) {
pin, err = readPIN()
if err != nil {
log.Fatalf("error reading PIN: %v", err)
}
continue
}
if err != nil {
log.Fatal(err)
}
break
}
fmt.Printf(
"key_handle: \"%s\"\npublic_key: \"%s\"\n",
base64.StdEncoding.EncodeToString(attest.CredentialID),
base64.StdEncoding.EncodeToString(fido2ToCOSE(attest.PubKey)),
)
}