Skip to content

Commit

Permalink
Initial import
Browse files Browse the repository at this point in the history
This is the initial implementation of the fido-hid pieces with a
an inmemory impl of the key management.
  • Loading branch information
psanford committed May 16, 2021
0 parents commit c63c9c5
Show file tree
Hide file tree
Showing 8 changed files with 1,196 additions and 0 deletions.
48 changes: 48 additions & 0 deletions attestation/attestation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package attestation

import (
"crypto/ecdsa"
"crypto/x509"
"encoding/pem"
)

// this is the same cert used by github/SoftU2F
// https://github.com/github/SoftU2F/blob/master/SelfSignedCertificate/SelfSignedCertificate.m
// We resuse that cert to help reduce the ability to track
// an individual using this cert

var attestationPrivateKeyPem = `-----BEGIN PRIVATE KEY-----
MHcCAQEEIAOEKsf0zeNn3qBWxk9/OxXqfUvEg8rGl58qMZOtVzEJoAoGCCqGSM49
AwEHoUQDQgAE9pyrJBRLtO+H9w8jHFzU9XgErPjgxrKz41IYPYA5H2vSedJqTINk
dObC2iOT/6wdUDRsXCOQZVeTPsuT/27e0Q==
-----END PRIVATE KEY-----`

var attestationCertPem = `-----BEGIN CERTIFICATE-----
MIIBcTCCARagAwIBAgIJAIqK93XCOr/GMAoGCCqGSM49BAMCMBMxETAPBgNVBAMM
CFNvZnQgVTJGMB4XDTE3MTAyMDIxNTEzM1oXDTI3MTAyMDIxNTEzM1owEzERMA8G
A1UEAwwIU29mdCBVMkYwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQ5gjPmSDFB
Jap5rwDMdyqO4lCcWqQXxXtHBN+S+zt6ytC3amquoctXGuOOKZikTkT/gX8LFXVq
mMZIcvC4EziGo1MwUTAdBgNVHQ4EFgQU8bJw2i1BjqI2uvqQWqNempxTxD4wHwYD
VR0jBBgwFoAU8bJw2i1BjqI2uvqQWqNempxTxD4wDwYDVR0TAQH/BAUwAwEB/zAK
BggqhkjOPQQDAgNJADBGAiEApFdcnvfziaAunldkAvHDwNViRH461fZv/6tFlbYP
GEwCIQCS1PM8fMOKTgdr3hpqeQq/ysQK8NJZtPbFADEk8effHQ==
-----END CERTIFICATE-----
`

var (
CertDer []byte
PrivateKey *ecdsa.PrivateKey
)

func init() {
certDer, _ := pem.Decode([]byte(attestationCertPem))
CertDer = certDer.Bytes

privKeyDer, _ := pem.Decode([]byte(attestationPrivateKeyPem))

var err error
PrivateKey, err = x509.ParseECPrivateKey(privKeyDer.Bytes)
if err != nil {
panic(err)
}
}
107 changes: 107 additions & 0 deletions fidoauth/fidoauth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// fidoauth implements the fido1 authentication API
package fidoauth

import (
"fmt"
"log"
)

const (
CmdRegister = 0x01
CmdAuthenticate = 0x02
CmdVersion = 0x03

CtrlCheckOnly AuthCtrl = 0x07 // Check if the provided key is valid
CtrlEnforeUserPresenceAndSign AuthCtrl = 0x03 // confirm with user then sign
CtrlDontEnforeUserPresenceAndSign AuthCtrl = 0x08 // just sign without confirming
)

type AuthenticatorRequest struct {
Command uint8
Param1 uint8
Param2 uint8
Size int
Data []byte

Register *AuthenticatorRegisterReq
Authenticate *AuthenticatorAuthReq
}

type AuthenticatorRegisterReq struct {
ChallengeParam [32]byte
ApplicationParam [32]byte
}

type AuthenticatorResponse struct {
Data []byte
Status uint16
}

type AuthCtrl uint8

type AuthenticatorAuthReq struct {
Ctrl AuthCtrl
ChallengeParam [32]byte
ApplicationParam [32]byte
KeyHandle []byte
}

func DecodeAuthenticatorRequest(raw []byte) (*AuthenticatorRequest, error) {
if len(raw) < 7 {
return nil, fmt.Errorf("authenticator request too short")
}

req := AuthenticatorRequest{
Command: raw[1],
Param1: raw[2],
Param2: raw[3],
Size: (int(raw[4]) << 16) | (int(raw[5]) << 8) | int(raw[6]),
Data: raw[7:],
}

log.Printf("got authenticatorrequest data: %+v", req.Data)

if req.Command == CmdRegister {
var reg AuthenticatorRegisterReq
if len(req.Data) < len(reg.ChallengeParam)+len(reg.ApplicationParam) {
return nil, fmt.Errorf("register request incorrect size: %d", len(req.Data))
}

copy(reg.ChallengeParam[:], req.Data[:32])
copy(reg.ApplicationParam[:], req.Data[32:])
req.Register = &reg
} else if req.Command == CmdAuthenticate {
var auth AuthenticatorAuthReq

if len(req.Data) < len(auth.ChallengeParam)+len(auth.ApplicationParam)+2 {
return nil, fmt.Errorf("authenticate request too small: %d", len(req.Data))
}

auth.Ctrl = AuthCtrl(req.Param1)

switch auth.Ctrl {
case CtrlCheckOnly, CtrlEnforeUserPresenceAndSign, CtrlDontEnforeUserPresenceAndSign:
default:
return nil, fmt.Errorf("unknown ctrl type: %02x", auth.Ctrl)
}

data := req.Data
copy(auth.ChallengeParam[:], data[:32])
data = data[32:]

copy(auth.ApplicationParam[:], data[:32])
data = data[32:]

khLen := data[0]
data = data[1:]

if len(data) < int(khLen) {
return nil, fmt.Errorf("key handle len too short %d vs %d", len(data), int(khLen))
}

auth.KeyHandle = data[:khLen]
req.Authenticate = &auth
}

return &req, nil
}
Loading

0 comments on commit c63c9c5

Please sign in to comment.