htlcswitch/failure: add Reextract to SphinxErrorEncrypter

This commit is contained in:
Conner Fromknecht 2018-03-12 13:36:25 -07:00
parent 75c7349823
commit dccab0a654
No known key found for this signature in database
GPG Key ID: 39DE78FBE6ACB0EF

@ -74,7 +74,7 @@ func (e UnknownEncrypterType) Error() string {
// ErrorEncrypterExtracter defines a function signature that extracts an // ErrorEncrypterExtracter defines a function signature that extracts an
// ErrorEncrypter from an sphinx OnionPacket. // ErrorEncrypter from an sphinx OnionPacket.
type ErrorEncrypterExtracter func(*sphinx.OnionPacket) (ErrorEncrypter, type ErrorEncrypterExtracter func(*btcec.PublicKey) (ErrorEncrypter,
lnwire.FailCode) lnwire.FailCode)
// ErrorEncrypter is an interface that is used to encrypt HTLC related errors // ErrorEncrypter is an interface that is used to encrypt HTLC related errors
@ -96,11 +96,20 @@ type ErrorEncrypter interface {
// backing this interface. // backing this interface.
Type() EncrypterType Type() EncrypterType
// Encode serializes the encrypter to the given io.Writer. // Encode serializes the encrypter's ephemeral public key to the given
// io.Writer.
Encode(io.Writer) error Encode(io.Writer) error
// Decode deserializes the encrypter from the given io.Reader. // Decode deserializes the encrypter' ephemeral public key from the
// given io.Reader.
Decode(io.Reader) error Decode(io.Reader) error
// Reextract rederives the encrypter using the extracter, performing an
// ECDH with the sphinx router's key and the ephemeral public key.
//
// NOTE: This should be called shortly after Decode to properly
// reinitialize the error encrypter.
Reextract(ErrorEncrypterExtracter) error
} }
// SphinxErrorEncrypter is a concrete implementation of both the ErrorEncrypter // SphinxErrorEncrypter is a concrete implementation of both the ErrorEncrypter
@ -110,14 +119,20 @@ type ErrorEncrypter interface {
type SphinxErrorEncrypter struct { type SphinxErrorEncrypter struct {
*sphinx.OnionErrorEncrypter *sphinx.OnionErrorEncrypter
ogPacket *sphinx.OnionPacket EphemeralKey *btcec.PublicKey
} }
// NewSphinxErrorEncrypter initializes a new sphinx error encrypter as well as // NewSphinxErrorEncrypter initializes a blank sphinx error encrypter, that
// the embedded onion error encrypter. // should be used to deserialize an encoded SphinxErrorEncrypter. Since the
// actual encrypter is not stored in plaintext while at rest, reconstructing the
// error encrypter requires:
// 1) Decode: to deserialize the ephemeral public key.
// 2) Reextract: to "unlock" the actual error encrypter using an active
// OnionProcessor.
func NewSphinxErrorEncrypter() *SphinxErrorEncrypter { func NewSphinxErrorEncrypter() *SphinxErrorEncrypter {
return &SphinxErrorEncrypter{ return &SphinxErrorEncrypter{
OnionErrorEncrypter: &sphinx.OnionErrorEncrypter{}, OnionErrorEncrypter: nil,
EphemeralKey: &btcec.PublicKey{},
} }
} }
@ -154,17 +169,56 @@ func (s *SphinxErrorEncrypter) Type() EncrypterType {
return EncrypterTypeSphinx return EncrypterTypeSphinx
} }
// Encode serializes the error encrypter to the provided io.Writer. // Encode serializes the error encrypter' ephemeral public key to the provided
// io.Writer.
func (s *SphinxErrorEncrypter) Encode(w io.Writer) error { func (s *SphinxErrorEncrypter) Encode(w io.Writer) error {
return s.OnionErrorEncrypter.Encode(w) ephemeral := s.EphemeralKey.SerializeCompressed()
_, err := w.Write(ephemeral)
return err
} }
// Decode reconstructs the error encrypter from the provided io.Reader. // Decode reconstructs the error encrypter's ephemeral public key from the
// provided io.Reader.
func (s *SphinxErrorEncrypter) Decode(r io.Reader) error { func (s *SphinxErrorEncrypter) Decode(r io.Reader) error {
if s.OnionErrorEncrypter == nil { var ephemeral [33]byte
s.OnionErrorEncrypter = &sphinx.OnionErrorEncrypter{} if _, err := io.ReadFull(r, ephemeral[:]); err != nil {
return err
} }
return s.OnionErrorEncrypter.Decode(r)
var err error
s.EphemeralKey, err = btcec.ParsePubKey(ephemeral[:], btcec.S256())
if err != nil {
return err
}
return nil
}
// Reextract rederives the error encrypter from the currently held EphemeralKey.
// This intended to be used shortly after Decode, to fully initialize a
// SphinxErrorEncrypter.
func (s *SphinxErrorEncrypter) Reextract(
extract ErrorEncrypterExtracter) error {
obfuscator, failcode := extract(s.EphemeralKey)
if failcode != lnwire.CodeNone {
// This should never happen, since we already validated that
// this obfuscator can be extracted when it was received in the
// link.
return fmt.Errorf("unable to reconstruct onion "+
"obfuscator, got failcode: %d", failcode)
}
sphinxEncrypter, ok := obfuscator.(*SphinxErrorEncrypter)
if !ok {
return fmt.Errorf("incorrect onion error extracter")
}
// Copy the freshly extracted encrypter.
s.OnionErrorEncrypter = sphinxEncrypter.OnionErrorEncrypter
return nil
} }
// A compile time check to ensure SphinxErrorEncrypter implements the // A compile time check to ensure SphinxErrorEncrypter implements the