// 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 }
// ImportVerified imports a verified key under the label. The original // signature data is preserved in the keystore. func (s *KeyStore) ImportVerified(label string, signedKey []byte) bool { var pub []byte if !s.Valid(true) || s.Has(label) { return false } var vkey VerifiedKey _, err := asn1.Unmarshal(signedKey, &vkey) if err != nil { return false } var signerLabel string if bytes.Equal(vkey.Signer, s.PublicKey) { signerLabel = "self" pub = s.PublicKey } else { var ok bool signerLabel, ok = s.FindPublic(vkey.Signer) if !ok { return false } pub = s.Keys[signerLabel].Keys } if signerLabel == "" || pub == nil { return false } else if _, ok := s.VerifyKeySignature(signerLabel); !ok { return false } pubkey, err := public.UnmarshalPublic(pub) if err != nil { return false } signatureData := vkey.SignatureData() if !public.Verify(pubkey, signatureData, vkey.Signature) { return false } rec := &PublicKeyRecord{ Label: label, Version: KeyStoreVersion, Timestamp: time.Now().Unix(), Keys: vkey.Public, KeySignature: vkey.Signature, KeySigner: pub, SignatureTime: vkey.Timestamp, } s.Keys[label] = rec return true }
func (s *KeyStore) getPublic(label string) *public.PublicKey { if !s.Has(label) { return nil } if label == "self" { if s.Locked() { pub, err := public.UnmarshalPublic(s.PublicKey) if err != nil { return nil } return pub } return s.privateKey.PublicKey } pub, err := public.UnmarshalPublic(s.Keys[label].Keys) if err != nil { return nil } return pub }
// IsSelfSigned returns true if the verified key is self-signed. func (vkey *VerifiedKey) IsSelfSigned() bool { if !bytes.Equal(vkey.Public, vkey.Signer) { return false } signer, err := public.UnmarshalPublic(vkey.Signer) if err != nil { return false } sigData := vkey.SignatureData() return public.Verify(signer, sigData, vkey.Signature) }
// KeySession sets up a new session from the user's private key and the // server's ephemeral public key. func KeySession(priv, pub []byte) (*Session, bool) { privKey, err := public.UnmarshalPrivate(priv) if err != nil { return nil, false } defer privKey.Zero() pubKey, err := public.UnmarshalPublic(pub) if err != nil { return nil, false } shared := public.KeyExchange(privKey, pubKey) return &Session{shared: shared}, true }
// EncryptTo encrypts the message to the named public key. func (s *KeyStore) EncryptTo(label string, message []byte) ([]byte, bool) { if !s.Valid(true) || !s.Has(label) { return nil, false } var pubBytes []byte if label == "self" { pubBytes = s.PublicKey } else { pubBytes = s.Keys[label].Keys } pub, err := public.UnmarshalPublic(pubBytes) if err != nil { return nil, false } return public.Encrypt(pub, message) }
// AddKey adds the new peer key to the keystore, signing it with the // owner's key. If the keystore is locked, this will fail. func (s *KeyStore) AddKey(label string, peer []byte, metadata map[string]string) bool { if !s.Valid(true) { return false } else if s.Has(label) { return false } else if s.Locked() { return false } else if _, err := public.UnmarshalPublic(peer); err != nil { return false } signTime := time.Now().Unix() vkey := &VerifiedKey{ Public: peer, Signer: s.PublicKey, Timestamp: signTime, } signatureData := vkey.SignatureData() sig, ok := public.Sign(s.privateKey, signatureData) if !ok { return false } if !public.Verify(s.privateKey.PublicKey, signatureData, sig) { return false } metadataCopy := map[string]string{} for k, v := range metadata { metadataCopy[k] = v } s.Keys[label] = &PublicKeyRecord{ Label: label, Timestamp: time.Now().Unix(), Keys: peer, KeySignature: sig, KeySigner: s.PublicKey, SignatureTime: signTime, Metadata: metadataCopy, } return true }
// 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 }
func testCreateOTP(t *testing.T) string { if sessionAuth == nil { t.Fatal("auth: session not established") } last, err := hex.DecodeString(sessionAuth.Last) if err != nil { t.Fatalf("%v", err) } sessionPublic, err := public.UnmarshalPublic(sessionPub) if err != nil { t.Fatalf("%v", err) } shared := public.KeyExchange(peerPrivate, sessionPublic) h := hmac.New(sha256.New, shared) h.Write(last) last = append(last, h.Sum(nil)...) return hex.EncodeToString(last) }
// VerifyKeySignature authenticates the signature on the key indicated // by label. If the label is self, Verify returns true as that label // is assumed always valid. func (s *KeyStore) VerifyKeySignature(label string) (string, bool) { if !s.Valid(true) { return "", false } if label == "self" { return "self", true } rec := s.Keys[label] var signerLabel string var vkey = &VerifiedKey{ Public: rec.Keys, Signature: rec.KeySignature, Timestamp: rec.SignatureTime, } if bytes.Equal(rec.KeySigner, s.PublicKey) { vkey.Signer = s.PublicKey signerLabel = "self" } else { var ok bool signerLabel, ok = s.FindPublic(rec.KeySigner) if !ok { return "", false } vkey.Signer = s.Keys[signerLabel].Keys } pub, err := public.UnmarshalPublic(vkey.Signer) if err != nil { return "", false } signatureData := vkey.SignatureData() if !public.Verify(pub, signatureData, vkey.Signature) { return "", false } return signerLabel, true }