Commit ae6f41fc authored by Caro Axel's avatar Caro Axel Committed by Loïck Bonniot

[c][t] Add resolve procedure calls

parent e520505e
Pipeline #2093 passed with stage
......@@ -74,14 +74,17 @@ func (m *SignatureManager) SendEvidence(promise *cAPI.Promise, signature *cAPI.S
if err == nil && result != nil && result.Code == pAPI.ErrorCode_SUCCESS {
m.archives.mutex.Lock()
if promise != nil {
dAPI.DLog("sent promise to " + mail)
dAPI.DLog("successfully sent promise to " + mail)
} else {
dAPI.DLog("sent signature to " + mail)
dAPI.DLog("successfully sent signature to " + mail)
m.archives.sentSignatures = append(m.archives.sentSignatures, signature)
}
m.archives.mutex.Unlock()
} else {
dAPI.DLog("unable to send evidence to " + mail)
dAPI.DLog("was unable to send evidence to " + mail)
if err != nil {
return
}
err = errors.New("received wrong error code")
}
......
......@@ -72,8 +72,10 @@ func (m *SignatureManager) Sign() error {
}
// Exchange messages
err = m.promiseRound(pendingSet, sendSet)
if err != nil {
var stop bool
stop, err = m.promiseRound(pendingSet, sendSet)
if err != nil || stop {
dAPI.DLog("stopping protocol execution")
return err
}
......@@ -115,7 +117,9 @@ func (m *SignatureManager) makeSignersHashToIDMap() {
}
// promiseRound describes a promise round: reception and sending
func (m *SignatureManager) promiseRound(pendingSet, sendSet []common.SequenceCoordinate) error {
// returns true if the client has to stop the protocol, false otherwise.
// returns an error if any occured.
func (m *SignatureManager) promiseRound(pendingSet, sendSet []common.SequenceCoordinate) (bool, error) {
// Reception of the due promises
var promises []*cAPI.Promise
for len(pendingSet) > 0 {
......@@ -131,11 +135,11 @@ func (m *SignatureManager) promiseRound(pendingSet, sendSet []common.SequenceCoo
}
promises = append(promises, promise)
} else {
return m.resolve()
return true, m.resolve()
}
case <-time.After(net.DefaultTimeout):
return m.resolve()
return true, m.resolve()
}
}
......@@ -143,24 +147,29 @@ func (m *SignatureManager) promiseRound(pendingSet, sendSet []common.SequenceCoo
m.updateReceivedPromises(promises)
m.lastValidIndex = m.currentIndex
c := make(chan *cAPI.Promise, chanBufferSize)
c := make(chan error, chanBufferSize)
// Sending of due promises
for _, coord := range sendSet {
go func(coord common.SequenceCoordinate, m *SignatureManager) {
promise, err := m.CreatePromise(m.myID, coord.Signer, uint32(m.currentIndex))
if err == nil {
_ = m.SendEvidence(promise, nil, coord.Signer)
err = m.SendEvidence(promise, nil, coord.Signer)
}
c <- promise
c <- err
}(coord, m)
}
// Verifying we sent all the due promises
for range sendSet {
<-c
v := <-c
if v != nil {
// We couldn't send a due promise
dAPI.DLog("Couldn't send promise: " + v.Error())
return true, m.resolve()
}
}
return nil
return false, nil
}
// closeConnections tries to close all established connection with other peers and platform.
......@@ -222,7 +231,7 @@ func (m *SignatureManager) callForResolve() (*tAPI.TTPResponse, error) {
toSend := append(m.archives.receivedPromises, selfPromise)
request := &tAPI.AlertRequest{Promises: toSend}
request := &tAPI.AlertRequest{Promises: toSend, Index: uint32(m.lastValidIndex)}
ctx, cancel := context.WithTimeout(context.Background(), net.DefaultTimeout)
defer cancel()
......@@ -241,9 +250,10 @@ func (m *SignatureManager) resolve() error {
return errors.New("No connection to TTP, aborting!")
}
dAPI.DLog("contacting TTP")
dAPI.DLog("contacting TTP with resolve index " + fmt.Sprint(m.lastValidIndex))
response, err := m.callForResolve()
if err != nil {
dAPI.DLog("Resolve call generated an error: " + err.Error())
return err
}
if response.Abort {
......
......@@ -3,6 +3,7 @@ package sign
import (
"dfss"
cAPI "dfss/dfssc/api"
dAPI "dfss/dfssd/api"
pAPI "dfss/dfssp/api"
"dfss/dfsst/entities"
"dfss/net"
......@@ -31,8 +32,10 @@ func (s *clientServer) TreatPromise(ctx context.Context, in *cAPI.Promise) (*pAP
// we do not check that we expected that promise
valid, _, _, _ := entities.IsRequestValid(ctx, []*cAPI.Promise{in})
if !valid {
dAPI.DLog("TreatPromise route did not treat promise from " + net.GetCN(&ctx) + " because it is invalid")
return &pAPI.ErrorCode{Code: pAPI.ErrorCode_SUCCESS}, nil
}
dAPI.DLog("TreatPromise route treated promise from " + net.GetCN(&ctx) + " because it is valid")
return getServerErrorCode(s.incomingPromises, in), nil
}
......
......@@ -25,14 +25,19 @@ func NewArchivesManager(db *mgdb.MongoManager) *ArchivesManager {
// InitializeArchives : if an entry in the database for this signature exists, retrieves it, otherwise creates it.
//
// This function should only be called after function IsRequestValid.
func (manager *ArchivesManager) InitializeArchives(promise *cAPI.Promise, signatureUUID bson.ObjectId, signers *[]Signer) {
func (manager *ArchivesManager) InitializeArchives(promise *cAPI.Promise, signatureUUID bson.ObjectId, signers *[]Signer) error {
present, archives := manager.ContainsSignature(signatureUUID)
if !present {
archives = NewSignatureArchives(signatureUUID, promise.Context.Sequence, *signers, promise.Context.ContractDocumentHash, promise.Context.Seal)
ok, err := manager.DB.Get("signatures").Insert(*archives)
if !ok {
return err
}
}
manager.Archives = archives
return nil
}
// ContainsSignature : checks if the specified signatureUUID matches a SignatureArchives in the database.
......@@ -70,10 +75,10 @@ func (manager *ArchivesManager) WasContractSigned() (bool, []byte) {
return false, []byte{}
}
// HasSignerPromised : determines if the specified signer has promised to sign to at least one other signer.
// HasSignerPromised : determines if the specified signer has promised to sign at least one time.
func (manager *ArchivesManager) HasSignerPromised(signer uint32) bool {
for _, p := range manager.Archives.ReceivedPromises {
if (p.SenderKeyIndex == signer) && (p.RecipientKeyIndex != signer) {
if p.SenderKeyIndex == signer {
return true
}
}
......
......@@ -88,27 +88,17 @@ func TestInitializeArchives(t *testing.T) {
Seal: seal,
},
}
archives := NewSignatureArchives(signatureUUIDBson, sequence, signersEntities, contractDocumentHash, seal)
manager := &ArchivesManager{
DB: dbManager,
Archives: archives,
}
arch := NewSignatureArchives(signatureUUIDBson, sequence, signersEntities, contractDocumentHash, seal)
manager.InitializeArchives(promise, signatureUUIDBson, &signersEntities)
err = manager.InitializeArchives(promise, signatureUUIDBson, &signersEntities)
assert.Nil(t, err)
arch.Signers = manager.Archives.Signers
assert.Equal(t, manager.Archives, arch)
ok, err := collection.Insert(manager.Archives)
assert.Equal(t, ok, true)
assert.Equal(t, err, nil)
manager.Archives = &SignatureArchives{}
manager.InitializeArchives(promise, signatureUUIDBson, &signersEntities)
assert.Equal(t, err, nil)
assert.Equal(t, manager.Archives, arch)
ok, err = collection.DeleteByID(*manager.Archives)
ok, err := collection.DeleteByID(*manager.Archives)
assert.Equal(t, err, nil)
assert.Equal(t, ok, true)
}
......@@ -209,7 +199,7 @@ func TestHasSignerPromised(t *testing.T) {
assert.Equal(t, len(archives.ReceivedPromises), 2)
ok = manager.HasSignerPromised(1)
assert.Equal(t, ok, false)
assert.Equal(t, ok, true)
promise2 := &Promise{
RecipientKeyIndex: 0,
......
......@@ -3,9 +3,11 @@ package resolve
import (
"errors"
"fmt"
cAPI "dfss/dfssc/api"
"dfss/dfssc/common"
dAPI "dfss/dfssd/api"
"dfss/dfsst/entities"
)
......@@ -15,19 +17,23 @@ import (
func ArePromisesComplete(promiseEntities []*entities.Promise, promise *cAPI.Promise, step uint32) bool {
expected, err := generateExpectedPromises(promise, step)
if err != nil {
dAPI.DLog("error occured during the generation of expected promises")
return false
}
if len(promiseEntities) != len(expected) {
dAPI.DLog("promise sets are not equal, nb received: " + fmt.Sprint(len(promiseEntities)) + " ; expected: " + fmt.Sprint(len(expected)))
return false
}
for _, p := range expected {
for i, p := range expected {
if !containsPromise(promiseEntities, p) {
dAPI.DLog("promise sets are not equal, promise at index: " + fmt.Sprint(i))
return false
}
}
dAPI.DLog("promise sets are equal")
return true
}
......@@ -39,42 +45,59 @@ func generateExpectedPromises(promise *cAPI.Promise, step uint32) ([]*entities.P
recipientH := promise.Context.RecipientKeyHash
recipientID, err := entities.GetIndexOfSigner(promise, recipientH)
if err != nil {
dAPI.DLog(err.Error())
return nil, err
}
if seq[int(step)] != recipientID {
// if step is 0, then it means that the resolve call occured during the first round.
// therefore, there is no way we can generate the signed contract.
// so we don't check the 0 case, because it has no consequence on the folloing of the resolve algorithm: an abort token will be sent
// checking the 0 case would cause an error in the consistency between of the resolve index and the promise recipient sequence index.
if (step != 0) && (seq[int(step)] != recipientID) {
dAPI.DLog("sequence index at step " + fmt.Sprint(int(step)) + " is " + fmt.Sprint(seq[int(step)]) + ", recipientID is " + fmt.Sprint(recipientID))
return nil, errors.New("Signer at step is not recipient")
}
currentIndex, err := common.FindNextIndex(seq, recipientID, -1)
if err != nil {
dAPI.DLog(err.Error())
return nil, err
}
dAPI.DLog("resolve index is: " + fmt.Sprint(step))
dAPI.DLog("first index is: " + fmt.Sprint(currentIndex))
for currentIndex <= int(step) {
dAPI.DLog("started generation round with currentIndex " + fmt.Sprint(currentIndex))
roundPromises, err := generationRound(seq, recipientID, currentIndex)
if err != nil {
dAPI.DLog("error occured during the generation round, currentIndex: " + fmt.Sprint(currentIndex))
return nil, err
}
dAPI.DLog(fmt.Sprint(len(roundPromises)) + " promises were generated for this round")
for _, p := range roundPromises {
res = addPromiseToExpected(res, p)
}
currentIndex, _ = common.FindNextIndex(seq, recipientID, currentIndex)
dAPI.DLog("total number of expected promises this far: " + fmt.Sprint(len(res)))
currentIndex, err = common.FindNextIndex(seq, recipientID, currentIndex)
if err != nil {
dAPI.DLog(err.Error())
}
// if it was the last occurence, then we finish
if currentIndex == -1 {
break
}
}
dAPI.DLog("promise from rounds have been generated")
selfPromise := &entities.Promise{
RecipientKeyIndex: recipientID,
SenderKeyIndex: recipientID,
SequenceIndex: step,
}
dAPI.DLog("adding self promise")
return append(res, selfPromise), nil
}
......
......@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"os"
"sync"
cAPI "dfss/dfssc/api"
"dfss/dfssc/security"
......@@ -22,18 +23,25 @@ import (
// InternalError : constant string used to return a generic error message through gRPC in case of an internal error.
const InternalError string = "Internal server error"
var mutex sync.Mutex
type ttpServer struct {
DB *mgdb.MongoManager
}
// Alert route for the TTP.
func (server *ttpServer) Alert(ctx context.Context, in *tAPI.AlertRequest) (*tAPI.TTPResponse, error) {
mutex.Lock()
defer mutex.Unlock()
valid, signatureUUID, signers, senderIndex := entities.IsRequestValid(ctx, in.Promises)
if !valid {
dAPI.DLog("invalid request from " + net.GetCN(&ctx))
return nil, errors.New(InternalError)
}
valid = int(in.Index) >= len(in.Promises[0].Context.Sequence)
dAPI.DLog("resolve index is: " + fmt.Sprint(in.Index))
valid = int(in.Index) < len(in.Promises[0].Context.Sequence)
if !valid {
dAPI.DLog("invalid sequence index from " + net.GetCN(&ctx))
return nil, errors.New(InternalError)
......@@ -42,8 +50,14 @@ func (server *ttpServer) Alert(ctx context.Context, in *tAPI.AlertRequest) (*tAP
// with the same signatureUUID (thus signed information) for all promises, and sent by a valid signer
// wrt to the signed signers' hashes
dAPI.DLog("Resolve request from " + net.GetCN(&ctx) + " is valid")
manager := entities.NewArchivesManager(server.DB)
manager.InitializeArchives(in.Promises[0], signatureUUID, &signers)
err := manager.InitializeArchives(in.Promises[0], signatureUUID, &signers)
if err != nil {
dAPI.DLog("error occured during the initialization of the signature archives")
return nil, err
}
// Now archives contains the new or already present SignatureArchives
// We check if we have already sent an abort token to the sender of the request
......@@ -56,6 +70,7 @@ func (server *ttpServer) Alert(ctx context.Context, in *tAPI.AlertRequest) (*tAP
// We check that the sender of the request sent valid and complete information
stop, message, tmpPromises, err := server.handleInvalidPromises(manager, in.Promises, senderIndex, in.Index)
if stop {
dAPI.DLog("invalid promise caused stop")
return message, err
}
// Now we are sure that the sender of the AlertRequest is not dishonest
......@@ -63,6 +78,7 @@ func (server *ttpServer) Alert(ctx context.Context, in *tAPI.AlertRequest) (*tAP
// We try to use the already generated contract if it exists
generated, contract := manager.WasContractSigned()
if generated {
dAPI.DLog("sending the signed contract")
return &tAPI.TTPResponse{
Abort: false,
Contract: contract,
......@@ -75,8 +91,9 @@ func (server *ttpServer) Alert(ctx context.Context, in *tAPI.AlertRequest) (*tAP
// Try to generate the contract now
message, err = server.handleContractGenerationTry(manager)
// We manually update the database
ok, _ := server.DB.Get("signatures").UpdateByID(manager.Archives)
ok, err := server.DB.Get("signatures").UpdateByID(*(manager.Archives))
if !ok {
dAPI.DLog("error during 'UpdateByID' l.81" + fmt.Sprint(err.Error()))
return nil, errors.New(InternalError)
}
......@@ -90,10 +107,12 @@ func (server *ttpServer) Alert(ctx context.Context, in *tAPI.AlertRequest) (*tAP
// If an error occurs during this process, it is returned.
func (server *ttpServer) handleAbortedSender(manager *entities.ArchivesManager, senderIndex uint32) (bool, *tAPI.TTPResponse, error) {
if manager.HasReceivedAbortToken(senderIndex) {
dAPI.DLog("Sender has already contacted the ttp. He is dishonnest.")
manager.AddToDishonest(senderIndex)
ok, _ := manager.DB.Get("signatures").UpdateByID(manager.Archives)
ok, err := manager.DB.Get("signatures").UpdateByID(*(manager.Archives))
if !ok {
dAPI.DLog("error during 'UpdateByID' l.99" + fmt.Sprint(err.Error()))
return true, nil, errors.New(InternalError)
}
......@@ -102,7 +121,7 @@ func (server *ttpServer) handleAbortedSender(manager *entities.ArchivesManager,
Contract: nil,
}, nil
}
dAPI.DLog("sender has never contacted the ttp before")
return false, nil, nil
}
......@@ -119,16 +138,30 @@ func (server *ttpServer) handleAbortedSender(manager *entities.ArchivesManager,
// If an error occurs during this process, it is returned.
func (server *ttpServer) handleInvalidPromises(manager *entities.ArchivesManager, promises []*cAPI.Promise, senderIndex, stepIndex uint32) (bool, *tAPI.TTPResponse, []*entities.Promise, error) {
valid, tmpPromises := entities.ArePromisesValid(promises)
if valid {
dAPI.DLog("received promises are valid")
}
complete := resolve.ArePromisesComplete(tmpPromises, promises[0], stepIndex)
if complete {
dAPI.DLog("received promises are complete")
}
if !valid || !complete {
if !valid {
dAPI.DLog("received promises are not valid")
}
if !complete {
dAPI.DLog("received promises are not complete")
}
manager.AddToAbort(senderIndex)
manager.AddToDishonest(senderIndex)
ok, _ := manager.DB.Get("signatures").UpdateByID(manager.Archives)
ok, err := manager.DB.Get("signatures").UpdateByID(*(manager.Archives))
if !ok {
dAPI.DLog("error during 'UpdateByID' l.132" + fmt.Sprint(err.Error()))
return true, nil, nil, errors.New(InternalError)
}
dAPI.DLog("sending an abort token")
return true, &tAPI.TTPResponse{
Abort: true,
Contract: nil,
......@@ -164,6 +197,7 @@ func (server *ttpServer) updateArchiveWithEvidence(manager *entities.ArchivesMan
func (server *ttpServer) handleContractGenerationTry(manager *entities.ArchivesManager) (*tAPI.TTPResponse, error) {
generated, contract := resolve.Solve(manager)
if !generated {
dAPI.DLog("contract couldn't be generated. Sending an abort token.")
return &tAPI.TTPResponse{
Abort: true,
Contract: nil,
......@@ -172,7 +206,7 @@ func (server *ttpServer) handleContractGenerationTry(manager *entities.ArchivesM
// We add the generated contract to the signatureArchives
manager.Archives.SignedContract = contract
dAPI.DLog("contract was generated. Sending the signed contract.")
return &tAPI.TTPResponse{
Abort: false,
Contract: contract,
......
......@@ -82,7 +82,6 @@ func TestRegisterAuth(t *testing.T) {
}
func registerAndAuth(client *exec.Cmd, mail, password, keySize string, authMail, authToken bool) error {
setLastArg(client, "register", false)
client.Stdin = strings.NewReader(
mail + "\n" +
......
package tests
import (
"bufio"
"io/ioutil"
"os"
"os/exec"
......@@ -140,16 +141,28 @@ func checkProofFile(t *testing.T, nb int) {
assert.Equal(t, nb, matches, "Invalid number of proof file(s)")
}
// TestSignContractFailure tests the signature with a faulty client.
// In this test, everything should not work fine, because client1 shutdowns way too early.
// TestSignContractFailure tests the signature with a faulty client, when contract can't be generated.
// In this test, everything should not work fine, because client3 shutdowns way too early.
func TestSignContractFailure(t *testing.T) {
signatureHelper(t, "1", 0)
}
// TestSignContractSuccess tests the signature with a faulty client, when contract can be generated.
// In this test, everything should not work fine, because client3 shutdowns way too early.
func TestSignContractSuccess(t *testing.T) {
signatureHelper(t, "2", 2)
}
// signatureHelper : launches a parametrized signature, with the number of rounds a client will accomplish before shutting down,
// and the number of proof files expected to be generated.
func signatureHelper(t *testing.T, round string, nbFiles int) {
// Setup
stop, clients, contractPath, contractFilePath := setupSignature(t)
defer stop()
// Configure client3 to be faulty
setLastArg(clients[2], "--stopbefore", true)
setLastArg(clients[2], "1", false)
setLastArg(clients[2], round, false)
setLastArg(clients[2], "sign", false)
// Sign!
......@@ -159,6 +172,7 @@ func TestSignContractFailure(t *testing.T) {
setLastArg(clients[i], contractPath, false)
go func(c *exec.Cmd, i int) {
c.Stdin = strings.NewReader(contractFilePath + "\npassword\nyes\n")
c.Stderr = bufio.NewWriter(os.Stdout)
output, _ := c.Output()
closeChannel <- output
}(clients[i], i)
......@@ -169,6 +183,6 @@ func TestSignContractFailure(t *testing.T) {
<-closeChannel
}
checkProofFile(t, 0)
checkProofFile(t, nbFiles)
time.Sleep(time.Second)
}
......@@ -50,6 +50,13 @@ func startPlatform(tmpDir string) (platform, ttp, demo *exec.Cmd, stop func(), c
return
}
// Start demonstrator
demo = exec.Command(demoPath, "--port", "9099", "nogui")
demo.Stdout = os.Stdout
demo.Stderr = os.Stderr
err = demo.Start()
time.Sleep(time.Second)
// Start platform
platform = exec.Command(path, "--db", dbURI, "--path", dir, "-p", testPort, "--ttps", ttpsPath, "-d", "localhost:9099", "-v", "start")
platform.Stdout = os.Stdout
......@@ -64,12 +71,6 @@ func startPlatform(tmpDir string) (platform, ttp, demo *exec.Cmd, stop func(), c
_ = ioutil.WriteFile(filepath.Join(ttp.Dir, "ca.pem"), ca, 0600)
err = ttp.Start()
// Start demonstrator
demo = exec.Command(demoPath, "--port", "9099", "nogui")
demo.Stdout = os.Stdout
demo.Stderr = os.Stderr
err = demo.Start()
stop = func() {
_ = platform.Process.Kill()
_ = ttp.Process.Kill()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment