Пример #1
0
// SignatureRequest treats external request to this service.
func (cs *CoSi) SignatureRequest(req *SignatureRequest) (network.Body, onet.ClientError) {
	if req.Roster.ID == onet.RosterID(uuid.Nil) {
		req.Roster.ID = onet.RosterID(uuid.NewV4())
	}
	tree := req.Roster.GenerateBinaryTree()
	tni := cs.NewTreeNodeInstance(tree, tree.Root, cosi.Name)
	pi, err := cosi.NewProtocol(tni)
	if err != nil {
		return nil, onet.NewClientErrorCode(4100, "Couldn't make new protocol: "+err.Error())
	}
	cs.RegisterProtocolInstance(pi)
	pcosi := pi.(*cosi.CoSi)
	pcosi.SigningMessage(req.Message)
	h, err := crypto.HashBytes(network.Suite.Hash(), req.Message)
	if err != nil {
		return nil, onet.NewClientErrorCode(4101, "Couldn't hash message: "+err.Error())
	}
	response := make(chan []byte)
	pcosi.RegisterSignatureHook(func(sig []byte) {
		response <- sig
	})
	log.Lvl3("Cosi Service starting up root protocol")
	go pi.Dispatch()
	go pi.Start()
	sig := <-response
	if log.DebugVisible() > 1 {
		fmt.Printf("%s: Signed a message.\n", time.Now().Format("Mon Jan 2 15:04:05 -0700 MST 2006"))
	}
	return &SignatureResponse{
		Hash:      h,
		Signature: sig,
	}, nil
}
Пример #2
0
// ProposeVote calls the 'accept'-vote on the current propose-configuration
func (i *Identity) ProposeVote(accept bool) onet.ClientError {
	log.Lvl3("Voting proposal")
	if i.Proposed == nil {
		return onet.NewClientErrorCode(ErrorConfigMissing, "No proposed config")
	}
	log.Lvlf3("Voting %t on %s", accept, i.Proposed.Device)
	if !accept {
		return nil
	}
	hash, err := i.Proposed.Hash()
	if err != nil {
		return onet.NewClientErrorCode(ErrorOnet, err.Error())
	}
	sig, err := crypto.SignSchnorr(network.Suite, i.Private, hash)
	if err != nil {
		return onet.NewClientErrorCode(ErrorOnet, err.Error())
	}
	pvr := &ProposeVoteReply{}
	cerr := i.Client.SendProtobuf(i.Cothority.RandomServerIdentity(), &ProposeVote{
		ID:        i.ID,
		Signer:    i.DeviceName,
		Signature: &sig,
	}, pvr)
	if cerr != nil {
		return cerr
	}
	if pvr.Data != nil {
		log.Lvl2("Threshold reached and signed")
		i.Config = i.Proposed
		i.Proposed = nil
	} else {
		log.Lvl2("Threshold not reached")
	}
	return nil
}
Пример #3
0
// SetChildrenSkipBlock creates a new SkipChain if that 'service' doesn't exist
// yet.
func (s *Service) SetChildrenSkipBlock(scsb *SetChildrenSkipBlock) (network.Body, onet.ClientError) {
	parentID := scsb.ParentID
	childID := scsb.ChildID
	parent, ok := s.getSkipBlockByID(parentID)
	if !ok {
		return nil, onet.NewClientErrorCode(ErrorBlockNotFound, "couldn't find skipblock")
	}
	child, ok := s.getSkipBlockByID(childID)
	if !ok {
		return nil, onet.NewClientErrorCode(ErrorBlockNotFound, "couldn't find skipblock")
	}
	child.ParentBlockID = parentID
	parent.ChildSL = NewBlockLink()
	parent.ChildSL.Hash = childID

	cerr := s.startPropagation([]*SkipBlock{child, parent})
	if cerr != nil {
		return nil, cerr
	}
	// Parent-block is always of type roster, but child-block can be
	// data or roster.
	reply := &SetChildrenSkipBlockReply{parent, child}
	s.save()

	return reply, nil
}
Пример #4
0
// signNewSkipBlock should start a BFT-signature on the newest block
// which will propagate and update all forward-links of all blocks.
// As a simple solution it verifies the validity of the block,
// simulates a signature and propagates the latest and newest block.
func (s *Service) signNewSkipBlock(latest, newest *SkipBlock) (*SkipBlock, *SkipBlock, error) {
	log.Lvl4("Signing new block", newest, "on block", latest)
	if newest != nil && newest.Roster == nil {
		log.Lvl3("Got a data-block")
		if newest.ParentBlockID.IsNull() {
			return nil, nil, onet.NewClientErrorCode(ErrorBlockNoParent, "Data skipblock without parent")
		}
		parent, ok := s.getSkipBlockByID(newest.ParentBlockID)
		if !ok {
			return nil, nil, onet.NewClientErrorCode(ErrorBlockNoParent, "Didn't find parent block")
		}
		newest.Roster = parent.Roster
	}
	// Now verify if it's a valid block
	if err := s.verifyNewSkipBlock(latest, newest); err != nil {
		return nil, nil, onet.NewClientErrorCode(ErrorVerification, "Verification of newest SkipBlock failed: "+err.Error())
	}

	// Sign it
	err := s.startBFTSignature(newest)
	if err != nil {
		return nil, nil, err
	}
	if err := newest.VerifySignatures(); err != nil {
		log.Error("Couldn't verify signature: " + err.Error())
		return nil, nil, err
	}

	newblocks := make([]*SkipBlock, 1)
	if latest == nil {
		// Genesis-block only
		newblocks[0] = newest
	} else {
		// Adjust forward-links if it's an additional block
		var err error
		newblocks, err = s.addForwardLinks(newest)
		if err != nil {
			return nil, nil, err
		}
		latest = newblocks[1]
	}

	// Store and propagate the new SkipBlocks
	log.Lvl4("Finished signing new block", newest)
	if err = s.startPropagation(newblocks); err != nil {
		return nil, nil, err
	}
	return latest, newblocks[0], nil
}
Пример #5
0
// CreateIdentity will register a new SkipChain and add it to our list of
// managed identities.
func (s *Service) CreateIdentity(ai *CreateIdentity) (network.Body, onet.ClientError) {
	log.Lvlf3("%s Creating new identity with config %+v", s, ai.Config)
	ids := &Storage{
		Latest: ai.Config,
	}
	log.Lvl3("Creating Root-skipchain")
	var cerr onet.ClientError
	ids.Root, cerr = s.skipchain.CreateRoster(ai.Roster, 2, 10,
		skipchain.VerifyNone, nil)
	if cerr != nil {
		return nil, cerr
	}
	log.Lvl3("Creating Data-skipchain")
	ids.Root, ids.Data, cerr = s.skipchain.CreateData(ids.Root, 2, 10,
		skipchain.VerifyNone, ai.Config)
	if cerr != nil {
		return nil, cerr
	}

	roster := ids.Root.Roster
	replies, err := s.propagateIdentity(roster, &PropagateIdentity{ids}, propagateTimeout)
	if err != nil {
		return nil, onet.NewClientErrorCode(ErrorOnet, err.Error())
	}
	if replies != len(roster.List) {
		log.Warn("Did only get", replies, "out of", len(roster.List))
	}
	log.Lvlf2("New chain is\n%x", []byte(ids.Data.Hash))
	s.save()

	return &CreateIdentityReply{
		Root: ids.Root,
		Data: ids.Data,
	}, nil
}
Пример #6
0
// ProposeSend only stores the proposed configuration internally. Signatures
// come later.
func (s *Service) ProposeSend(p *ProposeSend) (network.Body, onet.ClientError) {
	log.Lvl2(s, "Storing new proposal")
	sid := s.getIdentityStorage(p.ID)
	if sid == nil {
		return nil, onet.NewClientErrorCode(ErrorBlockMissing, "Didn't find Identity")
	}
	roster := sid.Root.Roster
	replies, err := s.propagateConfig(roster, p, propagateTimeout)
	if err != nil {
		return nil, onet.NewClientErrorCode(ErrorOnet, err.Error())
	}
	if replies != len(roster.List) {
		log.Warn("Did only get", replies, "out of", len(roster.List))
	}
	return nil, nil
}
Пример #7
0
// GetResponsible searches for the block that is responsible for us - for
// - Data - it's his parent
// - else - it's himself
func (sb *SkipBlock) GetResponsible(s *Service) (*onet.Roster, onet.ClientError) {
	el := sb.Roster
	if el == nil {
		// We're a data-block, so use the parent's Roster
		if sb.ParentBlockID.IsNull() {
			return nil, onet.NewClientErrorCode(ErrorBlockContent, "Didn't find a Roster")
		}
		parent, ok := s.getSkipBlockByID(sb.ParentBlockID)
		if !ok {
			return nil, onet.NewClientErrorCode(ErrorBlockNoParent, "No Roster and no parent")
		}
		if parent.Roster == nil {
			return nil, onet.NewClientErrorCode(ErrorBlockContent, "Parent doesn't have Roster")
		}
		el = parent.Roster
	}
	return el, nil
}
Пример #8
0
func (s *Service) startBFTSignature(block *SkipBlock) error {
	done := make(chan bool)
	// create the message we want to sign for this round
	msg := []byte(block.Hash)
	el, cerr := block.GetResponsible(s)
	if cerr != nil {
		return cerr
	}
	switch len(el.List) {
	case 0:
		return errors.New("Found empty Roster")
	case 1:
		return errors.New("Need more than 1 entry for Roster")
	}

	// Start the protocol
	tree := el.GenerateNaryTreeWithRoot(2, s.ServerIdentity())

	node, e := s.CreateProtocolOnet(skipchainBFT, tree)
	if e != nil {
		return onet.NewClientErrorCode(ErrorOnet, "Couldn't create new node: "+e.Error())
	}

	// Register the function generating the protocol instance
	root := node.(*bftcosi.ProtocolBFTCoSi)
	root.Msg = msg
	data, e := network.MarshalRegisteredType(block)
	if e != nil {
		return errors.New("Couldn't marshal block: " + cerr.Error())
	}
	root.Data = data

	// in testing-mode with more than one host and service per cothority-instance
	// we might have the wrong verification-function, so set it again here.
	root.VerificationFunction = s.bftVerify
	// function that will be called when protocol is finished by the root
	root.RegisterOnDone(func() {
		done <- true
	})
	go node.Start()
	select {
	case <-done:
		block.BlockSig = root.Signature()
		if len(block.BlockSig.Exceptions) != 0 {
			return errors.New("Not everybody signed off the new block")
		}
		if e := block.BlockSig.Verify(network.Suite, el.Publics()); e != nil {
			return errors.New("Couldn't verify signature")
		}
	case <-time.After(time.Second * 60):
		return errors.New("Timed out while waiting for signature")
	}
	return nil
}
Пример #9
0
// ProposeUpdate returns an eventual config-proposition
func (s *Service) ProposeUpdate(cnc *ProposeUpdate) (network.Body, onet.ClientError) {
	log.Lvl3(s, "Sending proposal-update to client")
	sid := s.getIdentityStorage(cnc.ID)
	if sid == nil {
		return nil, onet.NewClientErrorCode(ErrorBlockMissing, "Didn't find Identity")
	}
	sid.Lock()
	defer sid.Unlock()
	return &ProposeUpdateReply{
		Propose: sid.Proposed,
	}, nil
}
Пример #10
0
// GetUpdateChain returns a slice of SkipBlocks which describe the part of the
// skipchain from the latest block the caller knows of to the actual latest
// SkipBlock.
// Somehow comparable to search in SkipLists.
func (s *Service) GetUpdateChain(latestKnown *GetUpdateChain) (network.Body, onet.ClientError) {
	block, ok := s.getSkipBlockByID(latestKnown.LatestID)
	if !ok {
		return nil, onet.NewClientErrorCode(ErrorBlockNotFound, "Couldn't find latest skipblock")
	}
	// at least the latest know and the next block:
	blocks := []*SkipBlock{block}
	log.Lvl3("Starting to search chain")
	for len(block.ForwardLink) > 0 {
		link := block.ForwardLink[len(block.ForwardLink)-1]
		block, ok = s.getSkipBlockByID(link.Hash)
		if !ok {
			return nil, onet.NewClientErrorCode(ErrorBlockNotFound, "Missing block in forward-chain")
		}
		blocks = append(blocks, block)
	}
	log.Lvl3("Found", len(blocks), "blocks")
	reply := &GetUpdateChainReply{blocks}

	return reply, nil
}
Пример #11
0
// ConfigUpdate returns a new configuration update
func (s *Service) ConfigUpdate(cu *ConfigUpdate) (network.Body, onet.ClientError) {
	sid := s.getIdentityStorage(cu.ID)
	if sid == nil {
		return nil, onet.NewClientErrorCode(ErrorBlockMissing, "Didn't find Identity")
	}
	sid.Lock()
	defer sid.Unlock()
	log.Lvl3(s, "Sending config-update")
	return &ConfigUpdateReply{
		Config: sid.Latest,
	}, nil
}
Пример #12
0
// notify other services about new/updated skipblock
func (s *Service) startPropagation(blocks []*SkipBlock) onet.ClientError {
	log.Lvlf3("Starting to propagate for service %x", s.Context.ServerIdentity().ID[0:8])
	for _, block := range blocks {
		roster := block.Roster
		if roster == nil {
			// Suppose it's a dataSkipBlock
			sb, ok := s.getSkipBlockByID(block.ParentBlockID)
			if !ok {
				return onet.NewClientErrorCode(ErrorBlockNoParent, "Didn't find Roster nor parent")
			}
			roster = sb.Roster
		}
		replies, e := s.Propagate(roster, block, propagateTimeout)
		if e != nil {
			return onet.NewClientErrorCode(ErrorOnet, e.Error())
		}
		if replies != len(roster.List) {
			log.Warn("Did only get", replies, "out of", len(roster.List))
		}
	}
	return nil
}
Пример #13
0
// ConfigUpdate asks if there is any new config available that has already
// been approved by others and updates the local configuration
func (i *Identity) ConfigUpdate() onet.ClientError {
	log.Lvl3("ConfigUpdate", i)
	if i.Cothority == nil || len(i.Cothority.List) == 0 {
		return onet.NewClientErrorCode(ErrorListMissing, "Didn't find any list in the cothority")
	}
	cur := &ConfigUpdateReply{}
	err := i.Client.SendProtobuf(i.Cothority.RandomServerIdentity(),
		&ConfigUpdate{ID: i.ID}, cur)
	if err != nil {
		return err
	}
	// TODO - verify new config
	i.Config = cur.Config
	return nil
}
Пример #14
0
// LinkParentChildBlock sends a request to create a link from the parent to the
// child block and inversely. The child-block is supposed to already have
// the parentBlockID set and be accepted.
func (c *Client) LinkParentChildBlock(parent, child *SkipBlock) (*SkipBlock, *SkipBlock, onet.ClientError) {
	log.Lvl3(parent, child)
	if err := child.VerifySignatures(); err != nil {
		return nil, nil, onet.NewClientError(err)
	}
	if !bytes.Equal(parent.Hash, child.ParentBlockID) {
		return nil, nil, onet.NewClientErrorCode(ErrorBlockNoParent, "Child doesn't point to that parent")
	}
	host := parent.Roster.RandomServerIdentity()
	reply := &SetChildrenSkipBlockReply{}
	cerr := c.SendProtobuf(host, &SetChildrenSkipBlock{parent.Hash, child.Hash},
		reply)
	if cerr != nil {
		return nil, nil, cerr
	}
	return reply.Parent, reply.Child, nil
}
Пример #15
0
// AttachToIdentity proposes to attach it to an existing Identity
func (i *Identity) AttachToIdentity(ID ID) onet.ClientError {
	i.ID = ID
	cerr := i.ConfigUpdate()
	if cerr != nil {
		return cerr
	}
	if _, exists := i.Config.Device[i.DeviceName]; exists {
		return onet.NewClientErrorCode(ErrorAccountDouble, "Adding with an existing account-name")
	}
	confPropose := i.Config.Copy()
	confPropose.Device[i.DeviceName] = &Device{i.Public}
	cerr = i.ProposeSend(confPropose)
	if cerr != nil {
		return cerr
	}
	return nil
}
Пример #16
0
// ProposeSkipBlock takes a hash for the latest valid SkipBlock and a SkipBlock
// that will be verified. If the verification returns true, the new SkipBlock
// will be signed and added to the chain and returned.
// If the the latest block given is nil it verify if we are actually creating
// the first (genesis) block and creates it. If it is called with nil although
// there already exist previous blocks, it will return an error.
func (s *Service) ProposeSkipBlock(psbd *ProposeSkipBlock) (network.Body, onet.ClientError) {
	prop := psbd.Proposed
	var prev *SkipBlock

	if !psbd.LatestID.IsNull() {
		// We're appending a block to an existing chain
		var ok bool
		prev, ok = s.getSkipBlockByID(psbd.LatestID)
		if !ok {
			return nil, onet.NewClientErrorCode(ErrorBlockNotFound, "Didn't find latest block")
		}
		prop.MaximumHeight = prev.MaximumHeight
		prop.BaseHeight = prev.BaseHeight
		prop.ParentBlockID = prev.ParentBlockID
		prop.VerifierID = prev.VerifierID
		prop.Index = prev.Index + 1
		index := prop.Index
		for prop.Height = 1; index%prop.BaseHeight == 0; prop.Height++ {
			index /= prop.BaseHeight
			if prop.Height >= prop.MaximumHeight {
				break
			}
		}
		log.Lvl4("Found height", prop.Height, "for index", prop.Index,
			"and maxHeight", prop.MaximumHeight, "and base", prop.BaseHeight)
		prop.BackLinkIds = make([]SkipBlockID, prop.Height)
		pointer := prev
		for h := range prop.BackLinkIds {
			for pointer.Height < h+1 {
				var ok bool
				pointer, ok = s.getSkipBlockByID(pointer.BackLinkIds[0])
				if !ok {
					return nil, onet.NewClientErrorCode(ErrorBlockNotFound, "Didn't find convenient SkipBlock for height "+
						strconv.Itoa(h))
				}
			}
			prop.BackLinkIds[h] = pointer.Hash
		}
	} else {
		// A new chain is created, suppose all arguments in SkipBlock
		// are correctly set up
		prop.Index = 0
		if prop.MaximumHeight == 0 {
			return nil, onet.NewClientErrorCode(ErrorParameterWrong, "Set a maximumHeight > 0")
		}
		if prop.BaseHeight == 0 {
			return nil, onet.NewClientErrorCode(ErrorParameterWrong, "Set a baseHeight > 0")
		}
		prop.Height = prop.MaximumHeight
		prop.ForwardLink = make([]*BlockLink, 0)
		// genesis block has a random back-link:
		bl := make([]byte, 32)
		rand.Read(bl)
		prop.BackLinkIds = []SkipBlockID{SkipBlockID(bl)}
	}
	if prop.Roster != nil {
		prop.Aggregate = prop.Roster.Aggregate
	}
	el, cerr := prop.GetResponsible(s)
	if cerr != nil {
		return nil, cerr
	}
	prop.AggregateResp = el.Aggregate

	prop.updateHash()

	var err error
	prev, prop, err = s.signNewSkipBlock(prev, prop)
	if err != nil {
		return nil, onet.NewClientErrorCode(ErrorVerification, "Verification error: "+err.Error())
	}
	s.save()

	reply := &ProposedSkipBlockReply{
		Previous: prev,
		Latest:   prop,
	}
	return reply, nil
}
Пример #17
0
// ProposeVote takes int account a vote for the proposed config. It also verifies
// that the voter is in the latest config.
// An empty signature signifies that the vote has been rejected.
func (s *Service) ProposeVote(v *ProposeVote) (network.Body, onet.ClientError) {
	log.Lvl2(s, "Voting on proposal")
	// First verify if the signature is legitimate
	sid := s.getIdentityStorage(v.ID)
	if sid == nil {
		return nil, onet.NewClientErrorCode(ErrorBlockMissing, "Didn't find identity")
	}

	// Putting this in a function because of the lock which needs to be held
	// over all calls that might return an error.
	cerr := func() onet.ClientError {
		sid.Lock()
		defer sid.Unlock()
		log.Lvl3("Voting on", sid.Proposed.Device)
		owner, ok := sid.Latest.Device[v.Signer]
		if !ok {
			return onet.NewClientErrorCode(ErrorAccountMissing, "Didn't find signer")
		}
		if sid.Proposed == nil {
			return onet.NewClientErrorCode(ErrorConfigMissing, "No proposed block")
		}
		hash, err := sid.Proposed.Hash()
		if err != nil {
			return onet.NewClientErrorCode(ErrorOnet, "Couldn't get hash")
		}
		if _, exists := sid.Votes[v.Signer]; exists {
			return onet.NewClientErrorCode(ErrorVoteDouble, "Already voted for that block")
		}
		log.Lvl3(v.Signer, "voted", v.Signature)
		if v.Signature != nil {
			err = crypto.VerifySchnorr(network.Suite, owner.Point, hash, *v.Signature)
			if err != nil {
				return onet.NewClientErrorCode(ErrorVoteSignature, "Wrong signature: "+err.Error())
			}
		}
		return nil
	}()
	if cerr != nil {
		return nil, cerr
	}

	// Propagate the vote
	_, err := s.propagateConfig(sid.Root.Roster, v, propagateTimeout)
	if err != nil {
		return nil, onet.NewClientErrorCode(ErrorOnet, cerr.Error())
	}
	if len(sid.Votes) >= sid.Latest.Threshold ||
		len(sid.Votes) == len(sid.Latest.Device) {
		// If we have enough signatures, make a new data-skipblock and
		// propagate it
		log.Lvl3("Having majority or all votes")

		// Making a new data-skipblock
		log.Lvl3("Sending data-block with", sid.Proposed.Device)
		reply, cerr := s.skipchain.ProposeData(sid.Root, sid.Data, sid.Proposed)
		if cerr != nil {
			return nil, cerr
		}
		_, msg, _ := network.UnmarshalRegistered(reply.Latest.Data)
		log.Lvl3("SB signed is", msg.(*Config).Device)
		usb := &UpdateSkipBlock{
			ID:     v.ID,
			Latest: reply.Latest,
		}
		_, err = s.propagateSkipBlock(sid.Root.Roster, usb, propagateTimeout)
		if err != nil {
			return nil, onet.NewClientErrorCode(ErrorOnet, cerr.Error())
		}
		s.save()
		return &ProposeVoteReply{sid.Data}, nil
	}
	return nil, nil
}