Example #1
0
        /// <summary>
        /// Deposit a ballot.
        /// </summary>
        /// <param name="ballot">Ballot in signed envleope.</param>
        /// <returns>Vote receipt signed by the server.</returns>
        public Signed<VoteReceipt> Vote(
            IRpcConnection connection,
            Signed<Envelope> signedEnvelope)
        {
            if (signedEnvelope == null)
            throw new ArgumentNullException("ballot");

              if (Status != VotingStatus.Voting)
              {
            Logger.Log(LogLevel.Warning,
              "Connection {0}: Voter id {1} (unverified) tried to vote, but status was {2}.",
              connection.Id,
              signedEnvelope.Certificate.Id.ToString(),
              Status.ToString());
            throw new PiArgumentException(ExceptionCode.WrongStatusForOperation, "Wrong status for operation.");
              }

              if (!signedEnvelope.Verify(this.certificateStorage))
              {
            if (signedEnvelope.VerifySimple())
            {
              Logger.Log(LogLevel.Warning,
            "Connection {0}: Voter id {1} (unverified) tried to vote, but his certificate had state {2}.",
            connection.Id,
            signedEnvelope.Certificate.Id.ToString(),
            signedEnvelope.Certificate.Validate(this.certificateStorage).Text());
            }
            else
            {
              Logger.Log(LogLevel.Warning,
            "Connection {0}: Voter id {1} (unverified) tried to vote, but the signature on envelope was invalid.",
            connection.Id,
            signedEnvelope.Certificate.Id.ToString());
            }

            throw new PiArgumentException(ExceptionCode.VoteSignatureNotValid, "Vote signature not valid.");
              }

              if (!(signedEnvelope.Certificate is VoterCertificate))
              {
            Logger.Log(LogLevel.Warning,
              "Connection {0}: Voter id {1} (verified) tried to vote, but his certificate was not a voter certificate.",
              connection.Id,
              signedEnvelope.Certificate.Id.ToString());
            throw new PiArgumentException(ExceptionCode.NoVoterCertificate, "Not a voter certificate.");
              }

              if (Parameters.GroupId != ((VoterCertificate)signedEnvelope.Certificate).GroupId)
              {
            Logger.Log(LogLevel.Warning,
              "Connection {0}: Voter id {1} (verified) tried to vote, but his group id was {2} when it should have been {3}.",
              connection.Id,
              signedEnvelope.Certificate.Id.ToString(),
              ((VoterCertificate)signedEnvelope.Certificate).GroupId,
              Parameters.GroupId);
            throw new PiArgumentException(ExceptionCode.BadGroupIdInCertificate, "Wrong group id in certificate.");
              }

              var envelope = signedEnvelope.Value;

              if (envelope.Date.Subtract(DateTime.Now).TotalHours < -1d ||
              envelope.Date.Subtract(DateTime.Now).TotalHours > 1d)
              {
            Logger.Log(LogLevel.Warning,
              "Connection {0}: Voter id {1} (verified) tried to vote, but the envelope was created at {2} and pushed at {3}.",
              connection.Id,
              signedEnvelope.Certificate.Id.ToString(),
              envelope.Date.ToString(),
              DateTime.Now.ToString());
            throw new PiArgumentException(ExceptionCode.InvalidEnvelopeBadDateTime, "Invalid envelope. Date out of range.");
              }

              if (envelope.VoterId != signedEnvelope.Certificate.Id)
              {
            Logger.Log(LogLevel.Warning,
              "Connection {0}: Voter id {1} (verified) tried to vote, but the envelope voter id did not match his certificate.",
              connection.Id,
              signedEnvelope.Certificate.Id.ToString());
            throw new PiArgumentException(ExceptionCode.InvalidEnvelopeBadVoterId, "Invalid envelope. Voter id does not match.");
              }

              if (envelope.Ballots.Count != Parameters.Questions.Count())
              {
            Logger.Log(LogLevel.Warning,
              "Connection {0}: Voter id {1} (verified) tried to vote, but there were {2} ballots in the envelope for {3} questions.",
              connection.Id,
              signedEnvelope.Certificate.Id.ToString(),
              envelope.Ballots.Count,
              Parameters.Questions.Count());
            throw new PiArgumentException(ExceptionCode.InvalidEnvelopeBadBallotCount, "Invalid envelope. Ballot count does not match.");
              }

              for (int questionIndex = 0; questionIndex < parameters.Questions.Count(); questionIndex++)
              {
            var ballot = envelope.Ballots[questionIndex];
            var question = parameters.Questions.ElementAt(questionIndex);

            if (ballot.SumProves.Count != parameters.ProofCount)
            {
              Logger.Log(LogLevel.Warning,
            "Connection {0}: Voter id {1} (verified) tried to vote, but there were {2} sum proofs present where there sould have been {3}.",
            connection.Id,
            signedEnvelope.Certificate.Id.ToString(),
            ballot.SumProves.Count,
            parameters.ProofCount);
              throw new PiArgumentException(ExceptionCode.InvalidEnvelopeBadProofCount, "Invalid envelope. Number of sum prooves does not match.");
            }

            if (ballot.Votes.Count != question.Options.Count())
            {
              Logger.Log(LogLevel.Warning,
            "Connection {0}: Voter id {1} (verified) tried to vote, but there were {2} votes present for {3} options.",
            connection.Id,
            signedEnvelope.Certificate.Id.ToString(),
            ballot.Votes.Count,
            question.Options.Count());
              throw new PiArgumentException(ExceptionCode.InvalidEnvelopeBadVoteCount, "Invalid envelope. Vote count does not match.");
            }

            if (ballot.Votes.Any(vote => vote.RangeProves.Count != parameters.ProofCount))
            {
              Logger.Log(LogLevel.Warning,
            "Connection {0}: Voter id {1} (verified) tried to vote, but there was the wrong number of range proofs on a vote.",
            connection.Id,
            signedEnvelope.Certificate.Id.ToString());
              throw new PiArgumentException(ExceptionCode.InvalidEnvelopeBadProofCount, "Invalid envelope. Number of range prooves does not match.");
            }
              }

              bool hasVoted = DbConnection.ExecuteHasRows(
            "SELECT count(*) FROM envelope WHERE VotingId = @VotingId AND VoterId = @VoterId",
            "@VotingId", Id.ToByteArray(),
            "@VoterId", signedEnvelope.Certificate.Id.ToByteArray());
              if (hasVoted)
            throw new PiArgumentException(ExceptionCode.AlreadyVoted, "Voter has already voted.");

              MySqlTransaction transaction = DbConnection.BeginTransaction();

              MySqlCommand indexCommand = new MySqlCommand(
            "SELECT max(EnvelopeIndex) + 1 FROM envelope WHERE VotingId = @VotingId",
            DbConnection,
            transaction);
              indexCommand.Add("@VotingId", Id.ToByteArray());
              object indexObject = indexCommand.ExecuteScalar();
              int envelopeIndex = indexObject == DBNull.Value ? 1 : Convert.ToInt32(indexObject);

              MySqlCommand insertCommand = new MySqlCommand(
            "INSERT INTO envelope (VotingId, EnvelopeIndex, VoterId, Value) VALUES (@VotingId, @EnvelopeIndex, @VoterId, @Value)",
            DbConnection,
            transaction);
              insertCommand.Add("@VotingId", Id.ToByteArray());
              insertCommand.Add("@VoterId", signedEnvelope.Certificate.Id.ToByteArray());
              insertCommand.Add("@Value", signedEnvelope.ToBinary());
              insertCommand.Add("@EnvelopeIndex", envelopeIndex);
              insertCommand.ExecuteNonQuery();

              transaction.Commit();

              Logger.Log(LogLevel.Info,
            "Connection {0}: Envelope for certificate id {1} on voting id {2} stored.",
            connection.Id,
            signedEnvelope.Certificate.Id.ToString(),
            Id.ToString());

              VoteReceipt voteReceipt = new VoteReceipt(Parameters, signedEnvelope);

              return new Signed<VoteReceipt>(voteReceipt, this.serverCertificate);
        }
Example #2
0
        /// <summary>
        /// Deposit partial deciphers from an authority.
        /// </summary>
        /// <param name="signedPartialDecipherList">Partial decipher list.</param>
        public void DepositPartialDecipher(
            IRpcConnection connection,
            Signed<PartialDecipherList> signedPartialDecipherList)
        {
            if (signedPartialDecipherList == null)
            throw new ArgumentNullException("partialDecipherContainer");

              if (Status != VotingStatus.Deciphering)
              {
            Logger.Log(LogLevel.Warning, "Authority id {0} (unverified) tried to deposit his partial decipher, but the status was {1}.", signedPartialDecipherList.Certificate.Id.ToString(), Status.ToString());
            throw new InvalidOperationException("Wrong status for operation.");
              }

              PartialDecipherList partialDecipherList = signedPartialDecipherList.Value;

              Certificate certificate = GetAuthority(partialDecipherList.AuthorityIndex);

              if (!signedPartialDecipherList.Verify(this.certificateStorage, Parameters.VotingBeginDate))
              {
            if (signedPartialDecipherList.VerifySimple())
            {
              Logger.Log(LogLevel.Warning, "Authority id {0} (unverified) tried to deposit his partial decipher, but his certificate had state {1}.", signedPartialDecipherList.Certificate.Id.ToString(), signedPartialDecipherList.Certificate.Validate(this.certificateStorage, Parameters.VotingBeginDate).Text());
            }
            else
            {
              Logger.Log(LogLevel.Warning, "Authority id {0} (unverified) tried to deposit his partial decipher, but the signature was invalid.", signedPartialDecipherList.Certificate.Id.ToString());
            }

            throw new PiArgumentException(ExceptionCode.InvalidSignature, "Bad signature.");
              }

              if (!signedPartialDecipherList.Certificate.IsIdentic(certificate))
              {
            Logger.Log(LogLevel.Warning, "Authority id {0} (verified) tried to deposit his partial decipher, but his certificate did not match id {1} for authority index {2}.", signedPartialDecipherList.Certificate.Id.ToString(), certificate.Id.ToString(), partialDecipherList.AuthorityIndex);
            throw new PiArgumentException(ExceptionCode.AuthorityInvalid, "Not signed by proper authority.");
              }

              if (partialDecipherList.PartialDeciphers.Count < 4)
              {
            Logger.Log(LogLevel.Warning, "Authority id {0} (verified) tried to deposit his partial decipher, but there were only {1} parts instead of 4.", signedPartialDecipherList.Certificate.Id.ToString(), partialDecipherList.PartialDeciphers.Count);
            throw new PiArgumentException(ExceptionCode.AuthorityCountMismatch, "Your Pi-Vote client is outdated.");
              }

              bool exists = DbConnection.ExecuteHasRows(
            "SELECT count(*) FROM deciphers WHERE VotingId = @VotingId AND AuthorityIndex = @AuthorityIndex",
            "@VotingId", Id.ToByteArray(),
            "@AuthorityIndex", partialDecipherList.AuthorityIndex);
              if (exists)
            throw new ArgumentException("Authority has already deposited shares.");

              MySqlCommand insertCommand = new MySqlCommand("INSERT INTO deciphers (VotingId, AuthorityIndex, Value) VALUES (@VotingId, @AuthorityIndex, @Value)", DbConnection);
              insertCommand.Add("@VotingId", Id.ToByteArray());
              insertCommand.Add("@AuthorityIndex", partialDecipherList.AuthorityIndex);
              insertCommand.Add("@Value", signedPartialDecipherList.ToBinary());
              insertCommand.ExecuteNonQuery();

              Logger.Log(LogLevel.Info, "Connection {0}: Partical deciphers for certificate id {1} on voting id {2} stored.", connection.Id, signedPartialDecipherList.Certificate.Id.ToString(), Id.ToString());

              long depositedShareResponseCount = (long)DbConnection.ExecuteScalar(
            "SELECT count(*) FROM deciphers WHERE VotingId = @VotingId",
            "@VotingId", Id.ToByteArray());

              SendAdminAuthorityActivityMail(certificate, "deposited partial deciphers");

              if (depositedShareResponseCount == this.parameters.Thereshold + 1)
              {
            Status = VotingStatus.Finished;
              }
        }
Example #3
0
        /// <summary>
        /// Deposit a share part from authorities.
        /// </summary>
        /// <param name="signedSharePart">Share part.</param>
        public void DepositShares(
            IRpcConnection connection,
            Signed<SharePart> signedSharePart)
        {
            if (signedSharePart == null)
            throw new ArgumentNullException("shares");

              if (Status != VotingStatus.New)
              {
            Logger.Log(LogLevel.Warning,
              "Connection {0}: Authority id {1} (unverified) tried to deposit shares, but the status was {2}.",
              connection.Id,
              signedSharePart.Certificate.Id.ToString(),
              Status.ToString());
            throw new PiArgumentException(ExceptionCode.WrongStatusForOperation, "Wrong status for operation.");
              }

              SharePart sharePart = signedSharePart.Value;

              Certificate certificate = GetAuthority(sharePart.AuthorityIndex);

              if (!signedSharePart.Verify(this.certificateStorage, Parameters.VotingBeginDate))
              {
            if (signedSharePart.VerifySimple())
            {
              Logger.Log(LogLevel.Warning,
            "Connection {0}: Authority id {1} (unverified) tried to deposit shares, but his certificate had state {2}.",
            connection.Id,
            signedSharePart.Certificate.Id.ToString(),
            signedSharePart.Certificate.Validate(this.certificateStorage, Parameters.VotingBeginDate).Text());
            }
            else
            {
              Logger.Log(LogLevel.Warning,
            "Connection {0}: Authority id {1} (unverified) tried to deposit shares, but the signature was invalid.",
            connection.Id,
            signedSharePart.Certificate.Id.ToString());
            }

            throw new PiSecurityException(ExceptionCode.InvalidSignature, "Bad signature.");
              }

              if (!signedSharePart.Certificate.IsIdentic(certificate))
              {
            Logger.Log(LogLevel.Warning,
              "Connection {0}: Authority id {1} (verified) tried to deposit shares, but his certificate did not match id {2} for authority index {3}.",
              connection.Id,
              signedSharePart.Certificate.Id.ToString(),
              certificate.Id.ToString(),
              sharePart.AuthorityIndex);
            throw new PiSecurityException(ExceptionCode.NoAuthorizedAuthority, "Not signed by proper authority.");
              }

              bool exists = DbConnection.ExecuteHasRows(
            "SELECT count(*) FROM sharepart WHERE VotingId = @VotingId AND AuthorityIndex = @AuthorityIndex",
            "@VotingId", Id.ToByteArray(),
            "@AuthorityIndex", sharePart.AuthorityIndex);

              if (exists)
              {
            Logger.Log(LogLevel.Warning,
              "Connection {0}: uthority id {1} (verified) tried to deposit shares, these were already present.",
              connection.Id,
              signedSharePart.Certificate.Id.ToString());
            throw new PiArgumentException(ExceptionCode.AuthorityHasAlreadyDeposited, "Authority has already deposited shares.");
              }

              MySqlCommand insertCommand = new MySqlCommand("INSERT INTO sharepart (VotingId, AuthorityIndex, Value) VALUES (@VotingId, @AuthorityIndex, @Value)", DbConnection);
              insertCommand.Add("@VotingId", Id.ToByteArray());
              insertCommand.Add("@AuthorityIndex", sharePart.AuthorityIndex);
              insertCommand.Add("@Value", signedSharePart.ToBinary());
              insertCommand.ExecuteNonQuery();

              Logger.Log(LogLevel.Info,
            "Connection {0}: Shares for certificate id {1} on voting id {2} stored.",
            connection.Id,
            signedSharePart.Certificate.Id.ToString(), Id.ToString());

              long depositedSharePartCount = (long)DbConnection.ExecuteScalar(
            "SELECT count(*) FROM sharepart WHERE VotingId = @VotingId",
            "@VotingId", Id.ToByteArray());

              SendAdminAuthorityActivityMail(certificate, "deposited shares");

              if (depositedSharePartCount == this.parameters.AuthorityCount)
              {
            Status = VotingStatus.Sharing;
              }
        }
Example #4
0
        /// <summary>
        /// Add an authority.
        /// </summary>
        /// <param name="certificate">Authority to be added.</param>
        /// <returns>Index of the authority.</returns>
        public int AddAuthority(
            IRpcConnection connection,
            Certificate certificate)
        {
            if (certificate == null)
            throw new ArgumentNullException("certificate");
              if (certificate.Validate(this.certificateStorage) != CertificateValidationResult.Valid)
            throw new PiSecurityException(ExceptionCode.InvalidCertificate, "Authority certificate not valid.");
              if (!(certificate is AuthorityCertificate))
            throw new PiSecurityException(ExceptionCode.NoAuthorizedAuthority, "No an authority certificate.");

              MySqlTransaction transaction = DbConnection.BeginTransaction();

              MySqlCommand countCommand = new MySqlCommand("SELECT count(*) FROM authority WHERE VotingId = @VotingId", DbConnection, transaction);
              countCommand.Add("@VotingId", this.parameters.VotingId.ToByteArray());
              if ((long)countCommand.ExecuteScalar() >= this.parameters.AuthorityCount)
            throw new PiArgumentException(ExceptionCode.AlreadyEnoughAuthorities, "Already enough authorities.");

              MySqlCommand addedCommand = new MySqlCommand("SELECT count(*) FROM authority WHERE VotingId = @VotingId AND AuthorityId = @AuthorityId", DbConnection, transaction);
              addedCommand.Add("@VotingId", this.parameters.VotingId.ToByteArray());
              addedCommand.Add("@AuthorityId", certificate.Id.ToByteArray());
              if (addedCommand.ExecuteHasRows())
            throw new PiArgumentException(ExceptionCode.AuthorityAlreadyInVoting, "Already an authority of the voting.");

              MySqlCommand indexCommand = new MySqlCommand("SELECT max(AuthorityIndex) + 1 FROM authority WHERE VotingId = @VotingId", DbConnection, transaction);
              indexCommand.Add("@VotingId", this.parameters.VotingId.ToByteArray());
              object authorityIndexNull = indexCommand.ExecuteScalar();
              int authorityIndex = authorityIndexNull == DBNull.Value ? 1 : Convert.ToInt32((long)authorityIndexNull);

              MySqlCommand insertCommand = new MySqlCommand("INSERT INTO authority (VotingId, AuthorityIndex, AuthorityId, Certificate) VALUES (@VotingId, @AuthorityIndex, @AuthorityId, @Certificate)", DbConnection, transaction);
              insertCommand.Parameters.AddWithValue("@VotingId", this.parameters.VotingId.ToByteArray());
              insertCommand.Parameters.AddWithValue("@AuthorityIndex", authorityIndex);
              insertCommand.Parameters.AddWithValue("@AuthorityId", certificate.Id.ToByteArray());
              insertCommand.Parameters.AddWithValue("@Certificate", certificate.ToBinary());
              insertCommand.ExecuteNonQuery();

              Logger.Log(LogLevel.Info, "Connection {0}: Authority id {1} added to voting id {2}", connection.Id, certificate.Id.ToString(), Id.ToString());

              transaction.Commit();

              return authorityIndex;
        }