Custom Policy Assertions in WSE 3 - Part 1
One of the major new features in WSE 3.0 is the revamped policy system. This is in the form of predefined "turnkey security profiles" and an extensibility model to create your own policy assertions. In order to demonstrate these features I've developed a simple election system with these characteristics:
- only authorized voters can vote
- authorized voters can only vote once (this can be some arbitrary limit instead of one if desired)
- only voters know how they voted (ballots are confidential)
- voters can verify their ballot was tabulated correctly
1, 2, and 4 can be implemented without any special magic with any of the standard WSE assertions except anonymousForCertificateSecurity. User names, kerberos, x509, or a custom token can all be used to authenticate the voter. Obviously, the problem is the voter's identity is now tied to the ballot and the voter has to trust the service keep their vote confidential. Only anonymousForCertificateSecurity meets #3 among the standard assertions, but it makes 1, 2, and 4 impossible since now the voter's identity is never communicated let alone authenticated. One solution to this problem is to use blind signatures.
Blind signatures have applications in digital cash as well as election systems. In this system, blind signatures will allow the election authority to authorize the voter and then issue a valid signature for a ballot it never sees. Then when the voter casts the ballot, the election authority verifies the signature and tallies the vote, but the ballot itself has no linkage to any specific voter.
Generally the blind signature issuing process works like this:
- An author creates a message
- The author applies a blinding factor to the message effectively encrypting it and submits it to the issuer
- The issuer does any necessary authorization checks and issues a signature for blinded message
- The author unblinds the issued signature and now has a signature for the original message even though the issuer hasn't seen the original
RSA signatures can be used to implement blind signatures. The C# BigInteger Class at The Code Project made this easy to implement. (Make sure to pick up the getBytes() bug fix from the comments.)
There's a problem with just going through the steps above. Basically this is a service that takes in random bytes and signs them with it's private key, so what if I send you a blinded message saying you owe me $1 million? If you just issue the signature, now I have a message signed by you saying you owe me $1 million and I'm afraid I don't take checks. There's a couple ways to mitigate this. First, limit the domain that this signature is valid for, in this case ballots. Second, have the author submit several copies of the document differentiated only by a random id. Then randomly select one that will actually be signed and request blinding factors for the rest. If the rest are all valid then the probability the still blinded document is bogus is greatly reduced, the more documents unblinded and checked the lower the probability.
The process for this election system is:
- Voter fills out a ballot
- All possible ballots are generated
- N sets of all possible ballots are generated, within each set all the ballots have the same id, but each set has a different id
- Each set is blinded with a different blinding factor
- All these blinded ballots are sent off to the signature issuer
- The issuer authorizes the voter
- The issuer selects 1 set, and then requests the other N-1 blinding factors from the voter
- The issuer unblinds the N-1 sets and verifies all the ballots within are valid
- The issuer returns a signature for each ballot in the unblinded set
- The voter selects the signature that matches their preferences
- The voter sends the unblinded ballot and unblinded signature to be tabulated
- The signature is verified and the vote is counted
The tricky part here is the sheer volume of ballots necessary to ensure confidentiality and protect the issuer. A signature for every possible ballot is necessary, so the voter will receiver a signature it can use and the signature issuer won't know how the voter voted. The multiple sets of ballots reduces the probability that the issuers signs a ballot the voter is unauthorized to vote (it's for a different election, or precinct or something).
With a blind signature assertion let's see how to meet the 4 requirement:
- only authorized voters can vote - using any assertion with client credentials, the signature issuer can deny signatures to unauthorized voters
- authorized voters can only vote once (this can be some arbitrary limit instead of one if desired) - same as #1, but need to add tracking of how many signatures have been issued to a voter
- only voters know how they voted (ballots are confidential) - the voter obtains a blind signature first then casts a ballot using anonymousForCertificateSecurity, the service verifies the anonymous voter is authorized by verifying the signature
- voters can verify their ballot was tabulated correctly - only the voter knows their ballot id, so the service can make available a list ballot id's and how they voted. This prevents fraud by the election authority, but some form of nonrepudiation would be necessary prevent false claims of fraud from voters.
Thus concludes what turned into a pretty long part 1. In part 2 we'll lay out the general design of the system.
The other parts: