Exemple #1
0
func (s *Server) ShareMask(clientDH *ClientDH, serverPub *[]byte) error {
	pub, shared := s.shareSecret(UnmarshalPoint(s.suite, clientDH.Public))
	mask := MarshalPoint(shared)
	for r := 0; r < MaxRounds; r++ {
		if r == 0 {
			sha3.ShakeSum256(s.maskss[r][clientDH.Id], mask)
		} else {
			sha3.ShakeSum256(s.maskss[r][clientDH.Id], s.maskss[r-1][clientDH.Id])
		}
	}
	*serverPub = MarshalPoint(pub)
	return nil
}
Exemple #2
0
func (s *Server) ShareSecret(clientDH *ClientDH, serverPub *[]byte) error {
	pub, shared := s.shareSecret(UnmarshalPoint(s.suite, clientDH.Public))
	secret := MarshalPoint(shared)
	for r := 0; r < MaxRounds; r++ {
		if r == 0 {
			sha3.ShakeSum256(s.secretss[r][clientDH.Id], secret)
		} else {
			sha3.ShakeSum256(s.secretss[r][clientDH.Id], s.secretss[r-1][clientDH.Id])
		}
	}
	//s.secretss[clientDH.Id] = make([]byte, len(MarshalPoint(shared)))
	*serverPub = MarshalPoint(pub)
	return nil
}
Exemple #3
0
func CheckCommitment(commitment []byte, profile *proto.EncodedProfile) bool {
	// The hash used here is modeled as a random oracle. This means that SHA3
	// is fine but SHA2 is not (consider HMAC-SHA2 instead).
	var commitmentCheck [64]byte
	sha3.ShakeSum256(commitmentCheck[:], profile.Encoding) // the profile includes a nonce
	return bytes.Equal(commitment[:], commitmentCheck[:])
}
Exemple #4
0
// ServeIzkp returns an http.Handler that reads an input file and
// computes an interactive zero-knowledge proof-of-posession protocol.
// (This is completely unused, but isn't it cool?)
func ServeIzkp(fn string) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		b, err := ioutil.ReadFile(fn)
		if err != nil {
			glog.Errorf("error reading file %s: %s", fn, err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		chalString := r.Header.Get("x-izkp-challenge")
		if chalString == "" {
			glog.Infof("didn't receive a challenge, so using a raw hash")
			d := make([]byte, 64)
			sha3.ShakeSum256(d, b)
			w.Write(d)
			return
		}
		challenge := []byte(chalString)
		glog.Infof("received a challenge of length %d", len(challenge))
		h := sha3.New512()
		h.Write(challenge)
		h.Write(b)
		d := make([]byte, 64)
		h.Sum(d)
		w.Write(d)
		return
	}
}
Exemple #5
0
/////////////////////////////////
//Download
////////////////////////////////
func (s *Server) GetResponse(cmask ClientMask, response *[]byte) error {
	t := time.Now()
	round := cmask.Round % MaxRounds
	otherBlocks := make([][]byte, len(s.servers))
	var wg sync.WaitGroup
	for i := range otherBlocks {
		if i == s.id {
			otherBlocks[i] = make([]byte, BlockSize)
		} else {
			wg.Add(1)
			go func(i int, cmask ClientMask) {
				defer wg.Done()
				curBlock := <-s.rounds[round].xorsChan[i][cmask.Id]
				otherBlocks[i] = curBlock.Block
			}(i, cmask)
		}
	}
	wg.Wait()
	<-s.rounds[round].blocksRdy[cmask.Id]
	if cmask.Id == 0 && profile {
		fmt.Println(cmask.Id, "down_network:", time.Since(t))
	}
	r := ComputeResponse(s.rounds[round].allBlocks, cmask.Mask, s.secretss[round][cmask.Id])
	sha3.ShakeSum256(s.secretss[round][cmask.Id], s.secretss[round][cmask.Id])
	Xor(Xors(otherBlocks), r)
	*response = r
	return nil
}
func ShakeSum256(password string) []byte {
	buf := []byte(password)
	// A hash needs to be 64 bytes long to have 256-bit collision resistance.
	h := make([]byte, 64)
	// Compute a 64-byte hash of buf and put it in h.
	sha3.ShakeSum256(h, buf)
	return h
}
Exemple #7
0
func NewSHA3Shake256(payloadLen int) func() {
	input := NewRand(payloadLen)
	var hash = make([]byte, 64)

	return func() {
		sha3.ShakeSum256(hash, input)
	}
}
Exemple #8
0
func hashToCurve(m []byte) *edwards25519.ExtendedGroupElement {
	// H(n) = (f(h(n))^8)
	var hmb [32]byte
	sha3.ShakeSum256(hmb[:], m)
	var hm edwards25519.ExtendedGroupElement
	extra25519.HashToEdwards(&hm, &hmb)
	edwards25519.GeDouble(&hm, &hm)
	edwards25519.GeDouble(&hm, &hm)
	edwards25519.GeDouble(&hm, &hm)
	return &hm
}
Exemple #9
0
//TODO: need to select based on some pseudorandomness/gamma function?
//      Note that these challenges are different from those of cryptocurrency
func (v *Verifier) SelectChallenges(seed []byte) []int64 {
	challenges := make([]int64, v.beta*int(v.log2))
	rands := make([]byte, v.beta*int(v.log2)*8)
	sha3.ShakeSum256(rands, seed) //PRNG
	for i := range challenges {
		val, num := binary.Uvarint(rands[i*8 : (i+1)*8])
		if num < 0 {
			panic("Couldn't read PRNG")
		}
		challenges[i] = int64(val % uint64(v.size))
	}
	return challenges
}
Exemple #10
0
func (c *Client) DownloadSlot(slot int, rnd uint64) []byte {
	//all but one server uses the prng technique
	round := rnd % MaxRounds
	maskSize := len(c.maskss[round][0])
	finalMask := make([]byte, maskSize)
	SetBit(slot, true, finalMask)
	mask := Xors(c.maskss[round])
	Xor(c.maskss[round][c.myServer], mask)
	Xor(finalMask, mask)

	//one response includes all the secrets
	response := make([]byte, BlockSize)
	secretsXor := Xors(c.secretss[round])
	cMask := ClientMask{Mask: mask, Id: c.id, Round: rnd}

	t := time.Now()
	err := c.rpcServers[c.myServer].Call("Server.GetResponse", cMask, &response)
	if err != nil {
		log.Fatal("Could not get response: ", err)
	}

	if c.id == 0 && profile {
		fmt.Println(c.id, "down_network_total:", time.Since(t))
	}

	Xor(secretsXor, response)

	for i := range c.secretss[round] {
		sha3.ShakeSum256(c.secretss[round][i], c.secretss[round][i])
	}

	for i := range c.maskss[round] {
		sha3.ShakeSum256(c.maskss[round][i], c.maskss[round][i])
	}

	return response
}
Exemple #11
0
func TestKeyserverRejectsMissignedUpdate(t *testing.T) {
	dieOnCtrlC()
	kss, caPool, clks, _, ck, clientConfig, teardown := setupRealm(t, 3, 3)
	defer teardown()
	stop := stoppableSyncedClocks(clks)
	defer close(stop)

	waitForFirstEpoch(kss[0], clientConfig.Realms[0].VerificationPolicy.GetQuorum())

	clientTLS, err := clientConfig.Realms[0].ClientTLS.Config(ck)
	if err != nil {
		t.Fatal(err)
	}
	_, alicePk, aliceEntry, aliceProfile := doRegister(t, kss[0], clientConfig, clientTLS, caPool, clks[0].Now(), alice, 0, proto.Profile{
		Nonce: []byte("noncenoncenonceNONCE"),
		Keys:  map[string][]byte{"abc": []byte{1, 2, 3}, "xyz": []byte("TEST 456")},
	})

	var aliceKeyIdBytes [8]byte
	sha3.ShakeSum256(aliceKeyIdBytes[:], proto.MustMarshal(alicePk))
	aliceKeyid := binary.BigEndian.Uint64(aliceKeyIdBytes[:8])
	_, badSk, _ := ed25519.GenerateKey(rand.Reader)

	conn, err := grpc.Dial(kss[1].publicListen.Addr().String(), grpc.WithTransportCredentials(credentials.NewTLS(clientTLS)))
	if err != nil {
		t.Fatal(err)
	}
	updateC := proto.NewE2EKSPublicClient(conn)
	_, err = updateC.Update(context.Background(), &proto.UpdateRequest{
		Update: &proto.SignedEntryUpdate{
			NewEntry:   *aliceEntry,
			Signatures: map[uint64][]byte{aliceKeyid: ed25519.Sign(badSk, aliceEntry.Encoding)[:]},
		},
		Profile: *aliceProfile,
		LookupParameters: &proto.LookupRequest{
			UserId:            alice,
			QuorumRequirement: clientConfig.Realms[0].VerificationPolicy.GetQuorum(),
		},
	})
	if err == nil {
		t.Fatalf("update went through even though it was signed with the wrong key")
	}
}
Exemple #12
0
func VerifyLookup(cfg *proto.Config, user string, pf *proto.LookupProof, now time.Time) (keys map[string][]byte, err error) {
	if pf.UserId != "" && pf.UserId != user {
		return nil, fmt.Errorf("VerifyLookup: proof specifies different user ID: %q != %q", pf.UserId, user)
	}
	realm, err := GetRealmByUser(cfg, user)
	if err != nil {
		return nil, err
	}
	if !vrf.Verify(realm.VRFPublic, []byte(user), pf.Index, pf.IndexProof) {
		return nil, fmt.Errorf("VerifyLookup: VRF verification failed")
	}
	root, err := VerifyConsensus(realm, pf.Ratifications, now)
	if err != nil {
		return
	}

	verifiedEntryHash, err := reconstructTreeAndLookup(realm.TreeNonce, root, pf.Index, pf.TreeProof)
	if err != nil {
		return nil, fmt.Errorf("VerifyLookup: failed to verify the lookup: %v", err)
	}
	if verifiedEntryHash == nil {
		if pf.Entry != nil {
			return nil, fmt.Errorf("VerifyLookup: non-empty entry %x did not match verified lookup result <nil>", pf.Entry)
		}
		if pf.Profile != nil {
			return nil, fmt.Errorf("VerifyLookup: non-empty profile %x did not match verified lookup result <nil>", pf.Profile)
		}
		return nil, nil
	} else {
		var entryHash [32]byte
		sha3.ShakeSum256(entryHash[:], pf.Entry.Encoding)
		if !bytes.Equal(entryHash[:], verifiedEntryHash) {
			return nil, fmt.Errorf("VerifyLookup: entry hash %x did not match verified lookup result %x", entryHash, verifiedEntryHash)
		}

		if !CheckCommitment(pf.Entry.ProfileCommitment, pf.Profile) {
			return nil, fmt.Errorf("VerifyLookup: profile does not match the hash in the entry")
		}

		return pf.Profile.Keys, nil
	}
}
Exemple #13
0
func (ks *Keyserver) verifyUpdateEdge(req *proto.UpdateRequest) error {
	if len(req.Update.NewEntry.Index) != vrf.Size {
		return fmt.Errorf("index '%x' has wrong length (expected %d)", req.Update.NewEntry.Index, vrf.Size)
	}
	prevUpdate, err := ks.getUpdate(req.Update.NewEntry.Index, math.MaxUint64)
	if err != nil {
		log.Print(err)
		return fmt.Errorf("internal error")
	}
	if prevUpdate == nil { // registration: check email proof
		if !ks.insecureSkipEmailProof {
			email, payload, err := dkim.CheckEmailProof(req.DKIMProof, ks.emailProofToAddr,
				ks.emailProofSubjectPrefix, ks.lookupTXT, ks.clk.Now)
			if err != nil {
				return fmt.Errorf("failed to verify DKIM proof: %s", err)
			}
			if got, want := email, req.LookupParameters.UserId; got != want {
				return fmt.Errorf("requested user ID does not match the email proof: %q != %q", got, want)
			}
			lastAtIndex := strings.LastIndex(req.LookupParameters.UserId, "@")
			if lastAtIndex == -1 {
				return fmt.Errorf("requested user id is not a valid email address: %q", req.LookupParameters.UserId)
			}
			if _, ok := ks.emailProofAllowedDomains[req.LookupParameters.UserId[lastAtIndex+1:]]; !ok {
				return fmt.Errorf("domain not in registration whitelist: %q", req.LookupParameters.UserId[lastAtIndex+1:])
			}
			entryHash, err := base64.StdEncoding.DecodeString(payload)
			if err != nil {
				return fmt.Errorf("bad base64 in email proof: %q", payload)
			}
			var entryHashProposed [32]byte
			sha3.ShakeSum256(entryHashProposed[:], req.Update.NewEntry.Encoding)
			if !bytes.Equal(entryHashProposed[:], entryHash[:]) {
				return fmt.Errorf("email proof does not match requested entry: %s vs %s (%x)", base64.StdEncoding.EncodeToString(entryHashProposed[:]), payload, req.Update.NewEntry.Encoding)
			}
		}
	}

	return ks.verifyUpdateDeterministic(prevUpdate, req)
}
Exemple #14
0
// KeyID computes the ID of public key.
func KeyID(sv *PublicKey) uint64 {
	var h [8]byte
	sha3.ShakeSum256(h[:], MustMarshal(sv))
	return binary.LittleEndian.Uint64(h[:8])
}
Exemple #15
0
func doUpdate(
	t *testing.T, ks *Keyserver, clientConfig *proto.Config, clientTLS *tls.Config, caPool *x509.CertPool, now time.Time,
	name string, sk *[ed25519.PrivateKeySize]byte, pk *proto.PublicKey, version uint64, profileContents proto.Profile,
) (*proto.EncodedEntry, *proto.EncodedProfile) {
	conn, err := grpc.Dial(ks.publicListen.Addr().String(), grpc.WithTransportCredentials(credentials.NewTLS(clientTLS)))
	if err != nil {
		t.Fatal(err)
	}
	publicC := proto.NewE2EKSPublicClient(conn)

	// First, do a lookup to retrieve the index
	lookup, err := publicC.Lookup(context.Background(), &proto.LookupRequest{
		UserId: name,
		// We don't care about any signatures here; the server just needs to tell us the index.
		QuorumRequirement: &proto.QuorumExpr{
			Threshold:      0,
			Candidates:     []uint64{},
			Subexpressions: []*proto.QuorumExpr{},
		},
	})
	if err != nil {
		t.Fatal(err)
	}
	index := lookup.Index

	// Do the update
	var keyidBytes [8]byte
	sha3.ShakeSum256(keyidBytes[:], proto.MustMarshal(pk))
	keyid := binary.BigEndian.Uint64(keyidBytes[:8])

	profile := proto.EncodedProfile{
		Profile: profileContents,
	}
	profile.UpdateEncoding()
	var commitment [64]byte
	sha3.ShakeSum256(commitment[:], profile.Encoding)
	entry := proto.EncodedEntry{
		Entry: proto.Entry{
			Index:   index,
			Version: version,
			UpdatePolicy: &proto.AuthorizationPolicy{
				PublicKeys: map[uint64]*proto.PublicKey{keyid: pk},
				PolicyType: &proto.AuthorizationPolicy_Quorum{Quorum: &proto.QuorumExpr{
					Threshold:      1,
					Candidates:     []uint64{keyid},
					Subexpressions: []*proto.QuorumExpr{},
				},
				}},
			ProfileCommitment: commitment[:],
		},
	}
	entry.UpdateEncoding()
	proof, err := publicC.Update(context.Background(), &proto.UpdateRequest{
		Update: &proto.SignedEntryUpdate{
			NewEntry:   entry,
			Signatures: map[uint64][]byte{keyid: ed25519.Sign(sk, entry.Encoding)[:]},
		},
		Profile: profile,
		LookupParameters: &proto.LookupRequest{
			UserId:            name,
			QuorumRequirement: clientConfig.Realms[0].VerificationPolicy.GetQuorum(),
		},
	})
	if err != nil {
		t.Fatal(err)
	}
	if got, want := proof.Profile.Encoding, profile.Encoding; !bytes.Equal(got, want) {
		t.Errorf("updated profile didn't roundtrip: %x != %x", got, want)
	}
	_, err = coname.VerifyLookup(clientConfig, name, proof, now)
	if err != nil {
		t.Fatal(err)
	}
	return &entry, &profile
}
Exemple #16
0
func hash(clear string) string {
	h := make([]byte, 64)
	sha3.ShakeSum256(h, []byte(clear))

	return fmt.Sprintf("%x", h)
}
Exemple #17
0
// step is called by run and changes the in-memory state. No i/o allowed.
func (ks *Keyserver) step(step *proto.KeyserverStep, rs *proto.ReplicaState, wb kv.Batch) (deferredIO func()) {
	// ks: &const
	// step, rs, wb: &mut
	switch step.Type.(type) {
	case *proto.KeyserverStep_Update:
		index := step.GetUpdate().Update.NewEntry.Index
		prevUpdate, err := ks.getUpdate(index, math.MaxUint64)
		if err != nil {
			log.Printf("getUpdate: %s", err)
			ks.wr.Notify(step.UID, updateOutput{Error: fmt.Errorf("internal error")})
			return
		}
		if err := ks.verifyUpdateDeterministic(prevUpdate, step.GetUpdate()); err != nil {
			ks.wr.Notify(step.UID, updateOutput{Error: err})
			return
		}
		latestTree := ks.merkletree.GetSnapshot(rs.LatestTreeSnapshot)

		// sanity check: compare previous version in Merkle tree vs in updates table
		prevEntryHashTree, _, err := latestTree.Lookup(index)
		if err != nil {
			ks.wr.Notify(step.UID, updateOutput{Error: fmt.Errorf("internal error")})
			return
		}
		var prevEntryHash []byte
		if prevUpdate != nil {
			prevEntryHash = make([]byte, 32)
			sha3.ShakeSum256(prevEntryHash, prevUpdate.Update.NewEntry.Encoding)
		}
		if !bytes.Equal(prevEntryHashTree, prevEntryHash) {
			log.Fatalf("ERROR: merkle tree and DB inconsistent for index %x: %x vs %x", index, prevEntryHashTree, prevEntryHash)
		}

		var entryHash [32]byte
		sha3.ShakeSum256(entryHash[:], step.GetUpdate().Update.NewEntry.Encoding)
		newTree, err := latestTree.BeginModification()
		if err != nil {
			ks.wr.Notify(step.UID, updateOutput{Error: fmt.Errorf("internal error")})
			return
		}
		if err := newTree.Set(index, entryHash[:]); err != nil {
			log.Printf("setting index '%x' gave error: %s", index, err)
			ks.wr.Notify(step.UID, updateOutput{Error: fmt.Errorf("internal error")})
			return
		}
		rs.LatestTreeSnapshot = newTree.Flush(wb).Nr
		epochNr := rs.LastEpochDelimiter.EpochNumber + 1
		wb.Put(tableUpdateRequests(index, epochNr), proto.MustMarshal(step.GetUpdate()))
		ks.wr.Notify(step.UID, updateOutput{Epoch: epochNr})

		rs.PendingUpdates = true
		ks.updateEpochProposer()

		if rs.LastEpochNeedsRatification {
			// We need to wait for the last epoch to appear in the verifier log before
			// inserting this update.
			wb.Put(tableUpdatesPendingRatification(rs.NextIndexLog), proto.MustMarshal(step.GetUpdate().Update))
		} else {
			// We can deliver the update to verifiers right away.
			return ks.verifierLogAppend(&proto.VerifierStep{Type: &proto.VerifierStep_Update{Update: step.GetUpdate().Update}}, rs, wb)
		}

	case *proto.KeyserverStep_EpochDelimiter:
		if step.GetEpochDelimiter().EpochNumber <= rs.LastEpochDelimiter.EpochNumber {
			return // a duplicate of this step has already been handled
		}
		rs.LastEpochDelimiter = *step.GetEpochDelimiter()
		log.Printf("epoch %d", step.GetEpochDelimiter().EpochNumber)

		rs.PendingUpdates = false
		ks.resetEpochTimers(rs.LastEpochDelimiter.Timestamp.Time())
		// rs.ThisReplicaNeedsToSignLastEpoch might already be true, if a majority
		// signed that did not include us. This will make us skip signing the last
		// epoch, but that's fine.
		rs.ThisReplicaNeedsToSignLastEpoch = true
		// However, it's not okay to see a new epoch delimiter before the previous
		// epoch has been ratified.
		if rs.LastEpochNeedsRatification {
			log.Panicf("new epoch delimiter but last epoch not ratified")
		}
		rs.LastEpochNeedsRatification = true
		ks.updateEpochProposer()
		deferredIO = ks.updateSignatureProposer

		snapshotNumberBytes := make([]byte, 8)
		binary.BigEndian.PutUint64(snapshotNumberBytes, rs.LatestTreeSnapshot)
		wb.Put(tableMerkleTreeSnapshot(step.GetEpochDelimiter().EpochNumber), snapshotNumberBytes)

		latestTree := ks.merkletree.GetSnapshot(rs.LatestTreeSnapshot)
		rootHash, err := latestTree.GetRootHash()
		if err != nil {
			log.Panicf("ks.latestTree.GetRootHash() failed: %s", err)
		}
		teh := &proto.EncodedTimestampedEpochHead{TimestampedEpochHead: proto.TimestampedEpochHead{
			Head: proto.EncodedEpochHead{EpochHead: proto.EpochHead{
				RootHash:            rootHash,
				PreviousSummaryHash: rs.PreviousSummaryHash,
				Realm:               ks.realm,
				Epoch:               step.GetEpochDelimiter().EpochNumber,
				IssueTime:           step.GetEpochDelimiter().Timestamp,
			}, Encoding: nil},
			Timestamp: step.GetEpochDelimiter().Timestamp,
		}, Encoding: nil}
		teh.Head.UpdateEncoding()
		teh.UpdateEncoding()
		if rs.PreviousSummaryHash == nil {
			rs.PreviousSummaryHash = make([]byte, 64)
		}
		sha3.ShakeSum256(rs.PreviousSummaryHash[:], teh.Head.Encoding)

		wb.Put(tableEpochHeads(step.GetEpochDelimiter().EpochNumber), proto.MustMarshal(teh))

	case *proto.KeyserverStep_ReplicaSigned:
		newSEH := step.GetReplicaSigned()
		epochNr := newSEH.Head.Head.Epoch
		// get epoch head
		tehBytes, err := ks.db.Get(tableEpochHeads(epochNr))
		if err != nil {
			log.Panicf("get tableEpochHeads(%d): %s", epochNr, err)
		}
		// compare epoch head to signed epoch head
		if got, want := tehBytes, newSEH.Head.Encoding; !bytes.Equal(got, want) {
			log.Panicf("replica signed different head: wanted %x, got %x", want, got)
		}

		// insert all the new signatures into the ratifications table (there should
		// actually only be one)
		newSehBytes := proto.MustMarshal(newSEH)
		for id := range newSEH.Signatures {
			// the entry might already exist in the DB (if the proposals got
			// duplicated), but it doesn't matter
			wb.Put(tableRatifications(epochNr, id), newSehBytes)
		}

		deferredIO = func() {
			// First write to DB, *then* notify subscribers. That way, if subscribers
			// start listening before searching the DB, they're guaranteed to see the
			// signature: either it's already in the DB, or they'll get notified. If
			// the order was reversed, they could miss the notification but still not
			// see anything in the DB.
			ks.signatureBroadcast.Publish(epochNr, newSEH)
		}

		if epochNr != rs.LastEpochDelimiter.EpochNumber {
			break
		}
		if rs.ThisReplicaNeedsToSignLastEpoch && newSEH.Signatures[ks.replicaID] != nil {
			rs.ThisReplicaNeedsToSignLastEpoch = false
			ks.updateEpochProposer()
			// updateSignatureProposer should in general be called after writes
			// have been flushed to db, but given ThisReplicaNeedsToSignLast =
			// false we know that updateSignatureProposer will not access the db.
			ks.updateSignatureProposer()
		}
		// get all existing ratifications for this epoch
		allSignatures := make(map[uint64][]byte)
		existingRatifications, err := ks.allRatificationsForEpoch(epochNr)
		if err != nil {
			log.Panicf("allRatificationsForEpoch(%d): %s", epochNr, err)
		}
		for _, seh := range existingRatifications {
			for id, sig := range seh.Signatures {
				allSignatures[id] = sig
			}
		}
		// check whether the epoch was already ratified
		wasRatified := coname.VerifyPolicy(ks.serverAuthorized, tehBytes, allSignatures)
		if wasRatified {
			break
		}
		for id, sig := range newSEH.Signatures {
			allSignatures[id] = sig
		}
		// check whether the epoch has now become ratified
		nowRatified := coname.VerifyPolicy(ks.serverAuthorized, tehBytes, allSignatures)
		if !nowRatified {
			break
		}
		if !rs.LastEpochNeedsRatification {
			log.Panicf("%x: thought last epoch was not already ratified, but it was", ks.replicaID)
		}
		rs.LastEpochNeedsRatification = false
		ks.updateEpochProposer()
		var teh proto.EncodedTimestampedEpochHead
		err = teh.Unmarshal(tehBytes)
		if err != nil {
			log.Panicf("invalid epoch head %d (%x): %s", epochNr, tehBytes, err)
		}
		allSignaturesSEH := &proto.SignedEpochHead{
			Head:       teh,
			Signatures: allSignatures,
		}
		oldDeferredIO := deferredIO
		deferredSendEpoch := ks.verifierLogAppend(&proto.VerifierStep{Type: &proto.VerifierStep_Epoch{Epoch: allSignaturesSEH}}, rs, wb)
		deferredSendUpdates := []func(){}
		iter := ks.db.NewIterator(kv.BytesPrefix([]byte{tableUpdatesPendingRatificationPrefix}))
		defer iter.Release()
		for iter.Next() {
			update := &proto.SignedEntryUpdate{}
			err := update.Unmarshal(iter.Value())
			if err != nil {
				log.Panicf("invalid pending update %x: %s", iter.Value(), err)
			}
			deferredSendUpdates = append(deferredSendUpdates, ks.verifierLogAppend(&proto.VerifierStep{Type: &proto.VerifierStep_Update{Update: update}}, rs, wb))
			wb.Delete(iter.Key())
		}
		deferredIO = func() {
			oldDeferredIO()
			// First, send the ratified epoch to verifiers
			deferredSendEpoch()
			// Then send updates that were waiting for that epoch to go out
			for _, f := range deferredSendUpdates {
				f()
			}
		}

	case *proto.KeyserverStep_VerifierSigned:
		rNew := step.GetVerifierSigned()
		for id := range rNew.Signatures {
			// Note: The signature *must* have been authenticated before being inserted
			// into the log, or else verifiers could just trample over everyone else's
			// signatures, including our own.
			dbkey := tableRatifications(rNew.Head.Head.Epoch, id)
			wb.Put(dbkey, proto.MustMarshal(rNew))
		}
		ks.wr.Notify(step.UID, nil)
		return func() {
			// As above, first write to DB, *then* notify subscribers.
			ks.signatureBroadcast.Publish(rNew.Head.Head.Epoch, rNew)
		}
	default:
		log.Panicf("unknown step pb in replicated log: %#v", step)
	}
	return
}
Exemple #18
0
func (s *Server) handleResponses(round uint64) {
	rnd := round % MaxRounds
	allBlocks := <-s.rounds[rnd].dblocksChan
	//store it on this server as well
	s.rounds[rnd].allBlocks = allBlocks

	if s.FSMode {
		t := time.Now()

		for i := range allBlocks {
			s.rounds[rnd].upHashes[i] = allBlocks[i].Block[BlockSize:]
		}

		for i := range s.rounds[rnd].upHashesRdy {
			if s.clientMap[i] != s.id {
				continue
			}
			go func(i int) {
				s.rounds[rnd].upHashesRdy[i] <- true
			}(i)
		}

		var wg sync.WaitGroup
		for i := 0; i < s.totalClients; i++ {
			if s.clientMap[i] == s.id {
				continue
			}
			//if it doesnt belong to me, xor things and send it over
			wg.Add(1)
			go func(i int, rpcServer *rpc.Client, r uint64) {
				defer wg.Done()
				res := ComputeResponse(allBlocks, s.maskss[r][i], s.secretss[r][i])
				sha3.ShakeSum256(s.secretss[r][i], s.secretss[r][i])
				sha3.ShakeSum256(s.maskss[r][i], s.maskss[r][i])
				//fmt.Println(s.id, round, "mask", i, s.maskss[i])
				cb := ClientBlock{
					CId: i,
					SId: s.id,
					Block: Block{
						Block: res,
						Round: round,
					},
				}
				err := rpcServer.Call("Server.PutClientBlock", cb, nil)
				if err != nil {
					log.Fatal("Couldn't put block: ", err)
				}
			}(i, s.rpcServers[s.clientMap[i]], rnd)
		}
		wg.Wait()

		if profile {
			fmt.Println(s.id, "handling_resp:", time.Since(t))
		}
	}

	for i := range s.rounds[rnd].blocksRdy {
		if s.clientMap[i] != s.id {
			continue
		}
		go func(i int, round uint64) {
			s.rounds[rnd].blocksRdy[i] <- true
		}(i, round)
	}
}
Exemple #19
0
func main() {
	configPathPtr := flag.String("config", "clientconfig.json", "path to config file")
	name := flag.String("name", "*****@*****.**", "name to be looked up")
	lookupOnly := flag.Bool("lookup", false, "only lookup the name")
	flag.Parse()

	timeOut := 10 * time.Second
	configReader, err := os.Open(*configPathPtr)
	if err != nil {
		log.Fatalf("Failed to open configuration file: %s", err)
	}
	cfg := &proto.Config{}
	err = jsonpb.Unmarshal(configReader, cfg)
	if err != nil {
		log.Fatalf("Failed to parse configuration file: %s", err)
	}

	certFile := "ca.crt.pem"
	caCertPEM, err := ioutil.ReadFile(certFile)
	if err != nil {
		log.Fatalf("couldn't read certs from %s", certFile)
	}
	caCertDER, caCertPEM := pem.Decode(caCertPEM)
	if caCertDER == nil {
		log.Fatalf("failed to parse key PEM")
	}
	caCert, err := x509.ParseCertificate(caCertDER.Bytes)
	if err != nil {
		log.Fatal(err)
	}
	caPool := x509.NewCertPool()
	caPool.AddCert(caCert)

	realm := cfg.Realms[0]

	clientTLS, err := realm.ClientTLS.Config(getKey)
	if err != nil {
		log.Fatal(err)
	}
	conn, err := grpc.Dial(realm.Addr, grpc.WithTransportCredentials(credentials.NewTLS(clientTLS)), grpc.WithTimeout(timeOut))
	if err != nil {
		log.Fatal(err)
	}
	publicC := proto.NewE2EKSPublicClient(conn)

	// First, do a lookup to retrieve the index
	lookup, err := publicC.Lookup(context.Background(), &proto.LookupRequest{
		UserId: *name,
		// We don't care about any signatures here; the server just needs to tell us the index.
		// We could just give an empty quorum requirement if we wanted (although I guess the
		// spec actually disallows that).
		QuorumRequirement: realm.VerificationPolicy.GetQuorum(),
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("looking up %s:\n", *name)
	keys, err := coname.VerifyLookup(cfg, *name, lookup, time.Now())
	if err != nil {
		log.Fatal(err)
	}
	if keys == nil {
		fmt.Printf("not present\n")
	} else {
		fmt.Printf("keys: %s\n", keys)
	}
	index := lookup.Index

	if *lookupOnly {
		return
	}

	// Then, do the actual update
	nonce := make([]byte, 16)
	_, err = rand.Read(nonce)
	if err != nil {
		log.Fatal(err)
	}
	profile := proto.EncodedProfile{
		Profile: proto.Profile{
			Nonce: nonce,
			Keys:  map[string][]byte{"abc": []byte("foo bar"), "xyz": []byte("TEST 456")},
		},
	}
	profile.UpdateEncoding()
	var commitment [64]byte
	sha3.ShakeSum256(commitment[:], profile.Encoding)
	var version uint64
	if lookup.Entry != nil {
		version = lookup.Entry.Version + 1
	}
	entry := proto.EncodedEntry{
		Entry: proto.Entry{
			Index:   index,
			Version: version,
			UpdatePolicy: &proto.AuthorizationPolicy{
				PublicKeys: make(map[uint64]*proto.PublicKey),
				PolicyType: &proto.AuthorizationPolicy_Quorum{
					Quorum: &proto.QuorumExpr{
						Threshold:      0,
						Candidates:     []uint64{},
						Subexpressions: []*proto.QuorumExpr{},
					},
				},
			},
			ProfileCommitment: commitment[:],
		},
	}
	entry.UpdateEncoding()
	var entryHash [32]byte
	sha3.ShakeSum256(entryHash[:], entry.Encoding)

	fmt.Printf("updating profile:\n")
	proof, err := publicC.Update(context.Background(), &proto.UpdateRequest{
		Update: &proto.SignedEntryUpdate{
			NewEntry:   entry,
			Signatures: make(map[uint64][]byte),
		},
		Profile: profile,
		LookupParameters: &proto.LookupRequest{
			UserId:            *name,
			QuorumRequirement: realm.VerificationPolicy.GetQuorum(),
		},
		EmailProof: &proto.EmailProof{ProofType: &proto.EmailProof_DKIMProof{DKIMProof: []byte("X-Apparently-To: [email protected]; Mon, 31 Aug 2015 20:22:05 +0000\r\nReturn-Path: <*****@*****.**>\r\nReceived-SPF: pass (domain of yahoo-inc.com designates 216.145.54.155 as permitted sender)\r\nX-YMailISG: 1EhwNaYWLDv2gTUu.9nt0jxdqITV9b92O6Cwv1fdJI0Znuzw\r\n JiRKT62YsHZWJxcnlzt4SKtiChHTSAwHSy9.w97NwmcUQYqFkJkXmsqAjscY\r\n 0KW9efirs1q3YEvUtmN3BkIhbXujDW5L0Ne0YQtZnK.DF_Yi6dp7RCvfzUZf\r\n RskRPc2qP.tEMNji9_S1kSiPCtn8AwFsPHgGZtQOTtEYsTYUCsD4oEnjAJy1\r\n 332kCwDAOk1wj5l7.PwstEHF438ER_KZaMzfFq8UNrhdEwoFYZGSOfYeFV8W\r\n d2XMmN4vAJRV4D0FV9_cYwJRktzNvKqq.WddXZLuc96QR4.hxOOsq4gEEfJ8\r\n rkw8VodZEu_GlY_2lmyW8UBqmZLhO9lFuNsjfPVSVRyTxt4mMFBG_5XQudBO\r\n xudVy7LzRGiwH.3UlpR4Vl7smmSRC2bf4OrR0bZthRngty1VipzNCRVAE8Od\r\n ZjoR092JxYCF.B94f6ZF5FKqbB2QCjns3WKF0aExw.lzX8_Ral0DsXpBdan5\r\n aIU8cGBQuJBoaAjbaEanoVUXlvz0qXHLEDisvKKsc3w.igAQy01OCSik.2Gx\r\n m2XkGfeZ37mSdZhzAVKMR8eM8WkXl_O.uf7kq6vEyWXuhaMQonTjFYcdAtZX\r\n FMxFdkDTLp4bdEn1gu9JWyRYZTYnj3igBJxc0z_tIBlMrVpcf_NFpjBn1di2\r\n _sfojiKsnhUoYHwbjX7KT7yblcK8Re5Fp57g7XWIc2_tmRbY_iaiGhK0qr4x\r\n 72_hfaF0OBgArvDUPYWF50HYIP597qv1ucNyymAPVGxOx1UNOFWej494R6N1\r\n C8VTghtzKCbklLGGnmSIqPRZCZntvEsWHmmabhFwxRiTZQeu_HfN8CA_Gqoq\r\n k4qQgMbq9o22ekLsAj_jDEnUW343npUbD0XAYDOBCKuSRxZubpmXAu1HqmWL\r\n OTbpjEw8lvF_71EyG5qKVZoEiNCxXMUxia1FBp6RS_uDb4E73TgPxe1v1Ctw\r\n dzqBdg4G0DKkeMqDmDUzQUynHnonJpO4M5Bl6cdr2OfvYK7iDpPf1xeqoexb\r\n McFitNfwU6kax4VRMGahTFv2L56ovtsgV.NMuNEAwad_p3zI0kwi3OMfan9K\r\n _5pIOwQYuKc5vD.5Twq9KSOdYHGYZp_8cBv6dZ4UXvc9k1M5491nJ164VQo.\r\n v.qr6ufI2qhXdMTNxzsLw372.iYBA_5xPeT3dvaYt35sjzmjZnpN\r\nX-Originating-IP: [216.145.54.155]\r\nAuthentication-Results: mta2002.corp.mail.gq1.yahoo.com  from=yahoo-inc.com; domainkeys=neutral (no sig);  from=yahoo-inc.com; dkim=pass (ok)\r\nReceived: from 127.0.0.1  (EHLO mrout6.yahoo.com) (216.145.54.155)\r\n  by mta2002.corp.mail.gq1.yahoo.com with SMTPS; Mon, 31 Aug 2015 20:22:05 +0000\r\nReceived: from omp1018.mail.ne1.yahoo.com (omp1018.mail.ne1.yahoo.com [98.138.89.162])\r\n	by mrout6.yahoo.com (8.14.9/8.14.9/y.out) with ESMTP id t7VKLum2007505\r\n	(version=TLSv1/SSLv3 cipher=DHE-RSA-CAMELLIA256-SHA bits=256 verify=NO)\r\n	for <*****@*****.**>; Mon, 31 Aug 2015 13:21:56 -0700 (PDT)\r\nDKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=yahoo-inc.com;\r\n	s=cobra; t=1441052517;\r\n	bh=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN/XKdLCPjaYaY=;\r\n	h=Date:From:Reply-To:To:Subject;\r\n	b=bzbQnVqgZoDSfLYqlVlyv++8CntLQ2AQJR84uPzh2OF/mnz+m+H+YfzAzYQc7b+GU\r\n	 lGgG0DX89hnWgmp4U1LlzNqwUFrhmL8muanSejVHWkrX48grrG1OwNd5z04oO0hFJE\r\n	 20ql0lI4tkgSNR7JLoedMVNm/YdrmCiHbuMj2cxg=\r\nReceived: (qmail 99407 invoked by uid 1000); 31 Aug 2015 20:21:56 -0000\r\nDKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo-inc.com; s=ginc1024; t=1441052516; bh=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=; h=Date:From:Reply-To:To:Message-ID:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding; b=r+c21Nf78CMLaL0K1FmgE/CQz70nUJyVsSgQWqu9OlGdIf2GrY9OmwueQ4xHiLu4A5Jd0CAFgxLS5ZkBkPf4xUCvaLmQOYyY+8bfM2JhuG+g2dOMmjjajNqs+iyXfyx+Ak0T2Kahom/b7cpmr5/PiAb2JpL3O0p2StukvGAolp0=\r\nX-YMail-OSG: 0DtuWrwLUzvKrUMVVf5jtWesdteRmLR6oLTuKAGepU.3rTsZeR6zFmacnp0O_Dj\r\n RWZU-\r\nReceived: by 98.138.105.210; Mon, 31 Aug 2015 20:21:55 +0000 \r\nDate: Mon, 31 Aug 2015 20:21:55 +0000 (UTC)\r\nFrom: Daniel Ziegler <*****@*****.**>\r\nReply-To: Daniel Ziegler <*****@*****.**>\r\nTo: Daniel Ziegler <*****@*****.**>\r\nMessage-ID: <*****@*****.**>\r\nSubject: _YAHOO_E2E_KEYSERVER_PROOF_Y4ncLhJeE/qmdXlzCRp5JtgFHy4F4NbKPawk9U8vJ1E=\r\nMIME-Version: 1.0\r\nContent-Type: text/plain; charset=UTF-8\r\nContent-Transfer-Encoding: 7bit\r\nContent-Length: 1\r\n\r\n")}}})
	if err != nil {
		log.Fatalf("update failed on %s: %s", realm.Addr, err)
	}
	if got, want := proof.Profile.Encoding, profile.Encoding; !bytes.Equal(got, want) {
		log.Fatalf("created profile didn't roundtrip: %x != %x", got, want)
	}
	_, err = coname.VerifyLookup(cfg, *name, proof, time.Now())
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("success\n")
}
Exemple #20
0
// step is called by run and changes the in-memory state. No i/o allowed.
func (vr *Verifier) step(step *proto.VerifierStep, vs *proto.VerifierState, wb kv.Batch) (deferredIO func()) {
	// vr: &const
	// step, vs, wb: &mut
	switch step.Type.(type) {
	case *proto.VerifierStep_Update:
		index := step.GetUpdate().NewEntry.Index
		prevEntry, err := vr.getEntry(index, vs.NextEpoch)
		if err := coname.VerifyUpdate(prevEntry, step.GetUpdate()); err != nil {
			// the keyserver should filter all bad updates
			log.Panicf("%d: bad update %v: %s", vs.NextIndex, *step, err)
		}
		var entryHash [32]byte
		sha3.ShakeSum256(entryHash[:], step.GetUpdate().NewEntry.Encoding)
		latestTree := vr.merkletree.GetSnapshot(vs.LatestTreeSnapshot)
		newTree, err := latestTree.BeginModification()
		if err != nil {
			log.Panicf("%d: BeginModification(): %s", vs.NextIndex, err)
		}
		if err := newTree.Set(index, entryHash[:]); err != nil {
			log.Panicf("%d: Set(%x,%x): %s", vs.NextIndex, index, entryHash[:], err)
		}
		vs.LatestTreeSnapshot = newTree.Flush(wb).Nr
		wb.Put(tableEntries(index, vs.NextEpoch), step.GetUpdate().NewEntry.Encoding)

	case *proto.VerifierStep_Epoch:
		ok := coname.VerifyPolicy(vr.vs.KeyserverAuth, step.GetEpoch().Head.Encoding, step.GetEpoch().Signatures)
		// the bad steps here will not get persisted to disk right now. do we want them to?
		if !ok {
			log.Panicf("%d: keyserver signature verification failed: %#v", vs.NextIndex, *step)
		}
		r := step.GetEpoch().Head
		if r.Head.Realm != vr.realm {
			log.Panicf("%d: seh for realm %q, expected %q: %#v", vs.NextEpoch, r.Head.Realm, vr.realm, *step)
		}
		if r.Head.Epoch != vs.NextEpoch {
			log.Panicf("%d: got epoch %d instead: %#v", vs.NextEpoch, r.Head.Epoch, *step)
		}
		s := r.Head
		if !bytes.Equal(s.PreviousSummaryHash, vs.PreviousSummaryHash) {
			log.Panicf("%d: seh with previous summary hash %q, expected %q: %#v", vs.NextEpoch, s.PreviousSummaryHash, vs.PreviousSummaryHash, *step)
		}
		latestTree := vr.merkletree.GetSnapshot(vs.LatestTreeSnapshot)
		rootHash, err := latestTree.GetRootHash()
		if err != nil {
			log.Panicf("GetRootHash() failed: %s", err)
		}
		if !bytes.Equal(s.RootHash, rootHash) {
			log.Panicf("%d: seh with root hash %q, expected %q: %#v", vs.NextEpoch, s.RootHash, rootHash, *step)
		}
		seh := &proto.SignedEpochHead{
			Head: proto.EncodedTimestampedEpochHead{TimestampedEpochHead: proto.TimestampedEpochHead{
				Head:      s,
				Timestamp: proto.Time(time.Now()),
			}, Encoding: nil},
			Signatures: make(map[uint64][]byte, 1),
		}
		if vs.PreviousSummaryHash == nil {
			vs.PreviousSummaryHash = make([]byte, 64)
		}
		sha3.ShakeSum256(vs.PreviousSummaryHash[:], seh.Head.Head.Encoding)
		seh.Head.UpdateEncoding()
		seh.Signatures[vr.id] = ed25519.Sign(vr.signingKey, proto.MustMarshal(&seh.Head))[:]
		wb.Put(tableRatifications(vs.NextEpoch, vr.id), proto.MustMarshal(seh))
		vs.NextEpoch++
		return func() {
			_, err := vr.keyserver.PushRatification(vr.ctx, seh)
			if err != nil {
				log.Printf("PushRatification: %s", err)
			}
		}
	default:
		log.Panicf("%d: unknown step: %#v", vs.NextIndex, *step)
	}
	return
}
Exemple #21
0
func TestKeyserverUpdateFailsWithoutVersionIncrease(t *testing.T) {
	nReplicas := 3
	cfgs, gks, ck, clientConfig, _, caPool, _, teardown := setupKeyservers(t, nReplicas)
	defer teardown()
	logs, dbs, clks, _, teardown2 := setupRaftLogCluster(t, nReplicas, 0)
	defer teardown2()

	kss := []*Keyserver{}
	for i := range cfgs {
		ks, err := Open(cfgs[i], dbs[i], logs[i], clientConfig.Realms[0].VerificationPolicy, clks[i], gks[i], nil)
		if err != nil {
			t.Fatal(err)
		}
		ks.insecureSkipEmailProof = true
		ks.Start()
		defer ks.Stop()
		kss = append(kss, ks)
	}

	stop := stoppableSyncedClocks(clks)
	defer close(stop)

	waitForFirstEpoch(kss[0], clientConfig.Realms[0].VerificationPolicy.Quorum)

	clientTLS, err := clientConfig.Realms[0].ClientTLS.Config(ck)
	if err != nil {
		t.Fatal(err)
	}
	doUpdate(t, kss[0], clientConfig, clientTLS, caPool, clks[0].Now(), alice, 0, proto.Profile{
		Nonce: []byte("noncenoncenonceNONCE"),
		Keys:  map[string][]byte{"abc": []byte{1, 2, 3}, "xyz": []byte("TEST 456")},
	})

	conn, err := grpc.Dial(kss[1].publicListen.Addr().String(), grpc.WithTransportCredentials(credentials.NewTLS(clientTLS)))
	if err != nil {
		t.Fatal(err)
	}
	profile := proto.EncodedProfile{
		Profile: proto.Profile{
			Nonce: []byte("NONCE"),
			Keys:  map[string][]byte{"abc": []byte{3, 2, 3}, "xyz": []byte("TEST 456")},
		},
	}
	profile.UpdateEncoding()
	var commitment [64]byte
	sha3.ShakeSum256(commitment[:], profile.Encoding)
	entry := proto.EncodedEntry{
		Entry: proto.Entry{
			Version: 0,
			UpdatePolicy: &proto.AuthorizationPolicy{
				PublicKeys: make(map[uint64]*proto.PublicKey),
				Quorum: &proto.QuorumExpr{
					Threshold:      0,
					Candidates:     []uint64{},
					Subexpressions: []*proto.QuorumExpr{},
				},
			},
			ProfileCommitment: commitment[:],
		},
	}
	entry.UpdateEncoding()
	updateC := proto.NewE2EKSPublicClient(conn)
	_, err = updateC.Update(context.Background(), &proto.UpdateRequest{
		Update: &proto.SignedEntryUpdate{
			NewEntry:   entry,
			Signatures: make(map[uint64][]byte),
		},
		Profile: profile,
		LookupParameters: &proto.LookupRequest{
			UserId:            alice,
			QuorumRequirement: clientConfig.Realms[0].VerificationPolicy.Quorum,
		},
	})
	if err == nil {
		t.Fatalf("update went through despite failure to increment version")
	}
}
Exemple #22
0
func (ks *Keyserver) verifyUpdateEdge(req *proto.UpdateRequest) error {
	if len(req.Update.NewEntry.Index) != vrf.Size {
		return fmt.Errorf("index '%x' has wrong length (expected %d)", req.Update.NewEntry.Index, vrf.Size)
	}
	prevUpdate, err := ks.getUpdate(req.Update.NewEntry.Index, math.MaxUint64)
	if err != nil {
		log.Print(err)
		return fmt.Errorf("internal error")
	}
	if prevUpdate == nil { // registration: check email proof
		if !ks.insecureSkipEmailProof {
			if req.EmailProof == nil {
				return fmt.Errorf("No email proof provided")
			}

			lastAtIndex := strings.LastIndex(req.LookupParameters.UserId, "@")
			if lastAtIndex == -1 {
				return fmt.Errorf("requested user id is not a valid email address: %q", req.LookupParameters.UserId)
			}
			// determine registration type
			switch t := req.EmailProof.ProofType.(type) {
			case *proto.EmailProof_DKIMProof:
				if _, ok := ks.dkimProofAllowedDomains[req.LookupParameters.UserId[lastAtIndex+1:]]; !ok {
					return fmt.Errorf("domain not in registration whitelist: %q", req.LookupParameters.UserId[lastAtIndex+1:])

				}
				email, payload, err := dkim.CheckEmailProof(t.DKIMProof, ks.dkimProofToAddr, ks.dkimProofToAddr, ks.lookupTXT, ks.clk.Now)
				if err != nil {
					return fmt.Errorf("failed to verify DKIM proof: %s", err)
				}
				if got, want := email, req.LookupParameters.UserId; got != want {
					return fmt.Errorf("requested user ID does not match the email proof: %q != %q", got, want)
				}
				entryHash, err := base64.StdEncoding.DecodeString(payload)
				if err != nil {
					return fmt.Errorf("bad base64 in email proof: %q", payload)
				}
				var entryHashProposed [32]byte
				sha3.ShakeSum256(entryHashProposed[:], req.Update.NewEntry.Encoding)
				if !bytes.Equal(entryHashProposed[:], entryHash[:]) {
					return fmt.Errorf("email proof does not match requested entry: %s vs %s (%x)", base64.StdEncoding.EncodeToString(entryHashProposed[:]), payload, req.Update.NewEntry.Encoding)
				}

			case *proto.EmailProof_OIDCToken:
				found := false
				for _, oc := range ks.oidcProofConfig {
					if _, ok := oc.allowedDomains[req.LookupParameters.UserId[lastAtIndex+1:]]; !ok {
						continue
					}
					found = true
					email, err := oc.oidcClient.VerifyIDToken(t.OIDCToken)
					if err != nil {
						if _, ok := err.(*oidc.ErrExpired); ok {
							return &errExpired{err: err}
						}
						return err
					}
					if got, want := email, req.LookupParameters.UserId; got != want {
						return fmt.Errorf("requested user ID does not match the email proof: %q != %q", got, want)
					}
				}
				if !found {
					return fmt.Errorf("domain not in registration whitelist: %q", req.LookupParameters.UserId[lastAtIndex+1:])
				}

			case *proto.EmailProof_SAMLResponse:
				if _, ok := ks.samlProofAllowedDomains[req.LookupParameters.UserId[lastAtIndex+1:]]; !ok {
					return fmt.Errorf("domain not in registration whitelist: %q", req.LookupParameters.UserId[lastAtIndex+1:])

				}
				email, err := saml.VerifySAMLResponse(t.SAMLResponse, ks.samlProofIDPCert, ks.samlProofConsumerServiceURL, "EmailAddress", ks.samlProofValidity)
				if err != nil {
					if _, ok := err.(*saml.ErrExpired); ok {
						return &errExpired{err: err}
					}
					return err
				}
				if got, want := email, req.LookupParameters.UserId; got != want {
					return fmt.Errorf("requested user ID does not match the email proof: %q != %q", got, want)
				}

			default:
				return fmt.Errorf("Invalid email proof type: %T", t)
			}
		}
	}
	return ks.verifyUpdateDeterministic(prevUpdate, req)
}
Exemple #23
0
//share one time secret with the server
func (c *Client) ShareSecret() {
	gen := c.g.Point().Base()
	rand := c.suite.Cipher(abstract.RandomKey)
	secret1 := c.g.Scalar().Pick(rand)
	secret2 := c.g.Scalar().Pick(rand)
	public1 := c.g.Point().Mul(gen, secret1)
	public2 := c.g.Point().Mul(gen, secret2)

	//generate share secrets via Diffie-Hellman w/ all servers
	//one used for masks, one used for one-time pad
	cs1 := ClientDH{
		Public: MarshalPoint(public1),
		Id:     c.id,
	}
	cs2 := ClientDH{
		Public: MarshalPoint(public2),
		Id:     c.id,
	}

	masks := make([][]byte, len(c.servers))
	secrets := make([][]byte, len(c.servers))

	var wg sync.WaitGroup
	for i, rpcServer := range c.rpcServers {
		wg.Add(1)
		go func(i int, rpcServer *rpc.Client, cs1 ClientDH, cs2 ClientDH) {
			defer wg.Done()
			servPub1 := make([]byte, SecretSize)
			servPub2 := make([]byte, SecretSize)
			servPub3 := make([]byte, SecretSize)
			call1 := rpcServer.Go("Server.ShareMask", &cs1, &servPub1, nil)
			call2 := rpcServer.Go("Server.ShareSecret", &cs2, &servPub2, nil)
			call3 := rpcServer.Go("Server.GetEphKey", 0, &servPub3, nil)
			<-call1.Done
			<-call2.Done
			<-call3.Done
			masks[i] = MarshalPoint(c.g.Point().Mul(UnmarshalPoint(c.suite, servPub1), secret1))
			// c.masks[i] = make([]byte, SecretSize)
			// c.masks[i][c.id] = 1
			secrets[i] = MarshalPoint(c.g.Point().Mul(UnmarshalPoint(c.suite, servPub2), secret2))
			//secrets[i] = make([]byte, SecretSize)
			c.ephKeys[i] = UnmarshalPoint(c.suite, servPub3)
		}(i, rpcServer, cs1, cs2)
	}
	wg.Wait()

	for r := range c.secretss {
		for i := range c.secretss[r] {
			if r == 0 {
				sha3.ShakeSum256(c.secretss[r][i], secrets[i])
			} else {
				sha3.ShakeSum256(c.secretss[r][i], c.secretss[r-1][i])
			}
		}
	}

	for r := range c.maskss {
		for i := range c.maskss[r] {
			if r == 0 {
				sha3.ShakeSum256(c.maskss[r][i], masks[i])
			} else {
				sha3.ShakeSum256(c.maskss[r][i], c.maskss[r-1][i])
			}
		}
	}

}
Exemple #24
0
// ComputeCryptoHash should be used in openchain code so that we can change the actual algo used for crypto-hash at one place
func ComputeCryptoHash(data []byte) (hash []byte) {
	hash = make([]byte, 64)
	sha3.ShakeSum256(hash, data)
	return
}