// TestSessionSetup validates creating a new session and successful // validation of an OTP. func TestSessionSetup(t *testing.T) { var err error peerPrivate, err = public.GenerateKey() if err != nil { t.Fatalf("%v", err) } peer, err = public.MarshalPublic(peerPrivate.PublicKey) if err != nil { t.Fatalf("%v", err) } sessionAuth, sessionPub, err = NewSession(peer) if err != nil { t.Fatalf("%v", err) } newOTP := testCreateOTP(t) shouldUpdate, err := ValidateSession(sessionAuth, newOTP) if err != nil { t.Fatalf("%v", err) } if !shouldUpdate { t.Fatal("auth: ValidateSession should signal that an update is required") } }
// NewSession sets up a new session. The Last field should be sent // to the client. The returned public key should be sent to the // user for generating a shared MAC key. The authenticator should ensure // some mechanism for expiring sessions exists. func NewSession(pub []byte) (*Authenticator, []byte, error) { next := util.RandBytes(sessionLength) if next == nil { return nil, nil, errors.New("auth: PRNG failure") } ephemeral, err := public.GenerateKey() if err != nil || !ephemeral.Valid() { return nil, nil, errors.New("auth: failed to set up session key") } // Validated that the key was correct previously. ephemeralPublic, _ := public.MarshalPublic(ephemeral.PublicKey) peer, err := public.UnmarshalPublic(pub) if err != nil { return nil, nil, err } shared := public.KeyExchange(ephemeral, peer) return &Authenticator{ Type: TypeSession, Last: hex.EncodeToString(next), Secret: shared, }, ephemeralPublic, nil }
// Unlock decrypts the private key stored in the keystore. func (s *KeyStore) Unlock(passphrase []byte) bool { if !s.Valid(true) { return false } else if !s.Locked() { return true } priv, ok := public.UnlockKey(s.PrivateKey, passphrase) if !ok { return false } pub, err := public.MarshalPublic(priv.PublicKey) if err != nil { priv.Zero() return false } s.privateKey = priv s.PublicKey = pub s.locked = false if s.ExportKey == nil { fmt.Println("Building export key.") vkey := &VerifiedKey{ Public: s.PublicKey, Signer: s.PublicKey, Timestamp: time.Now().Unix(), } signatureData := vkey.SignatureData() sig, ok := public.Sign(s.privateKey, signatureData) if !ok { s.Lock() return false } vkey.Signature = sig verified, err := vkey.Serialise() if err != nil { s.Lock() return false } s.ExportKey = verified } return !s.Locked() }
// Valid performs sanity checks on the keystore to make sure it is // valid. If quick is false, the public key and private key (if // unlocked) will be checked as well. func (s *KeyStore) Valid(quick bool) bool { if s == nil { return false } if s.Version != KeyStoreVersion { return false } if s.Timestamp == 0 { return false } if s.Keys == nil { return false } if quick { return true } if !s.locked { if !s.privateKey.Valid() { return false } pub, err := public.MarshalPublic(s.privateKey.PublicKey) if err != nil { return false } if !bytes.Equal(pub, s.PublicKey) { return false } } if s.PublicKey == nil { return false } else if _, err := public.UnmarshalPublic(s.PublicKey); err != nil { return false } return true }
// NewPrivateKeyStore builds a keystore from a private key. func NewPrivateKeyStore(priv *public.PrivateKey) (*KeyStore, bool) { if !priv.Valid() { return nil, false } pub, err := public.MarshalPublic(priv.PublicKey) if err != nil { return nil, false } vkey := &VerifiedKey{ Public: pub, Signer: pub, Timestamp: time.Now().Unix(), } signatureData := vkey.SignatureData() sig, ok := public.Sign(priv, signatureData) if !ok { return nil, false } vkey.Signature = sig verified, err := vkey.Serialise() if err != nil { return nil, false } return &KeyStore{ Version: KeyStoreVersion, Timestamp: time.Now().Unix(), Keys: map[string]*PublicKeyRecord{}, privateKey: priv, locked: false, PublicKey: pub, ExportKey: verified, }, true }