Me and my PPID: Can I rely on it?
With CardSpace, the PPID is a claim that the built-in STS will generate. It’s the only claim that a personal card can have that the user doesn’t get to control.
How it is made
When a user goes to present a personal card to a relying party, and generate a security token, CardSpace takes the SSL certificate of the relying party, and, with the Master Key, uses data from the certificate to create two things: a public/private key-pair and the PPID. The data that it uses from the certificate depends on what type of certificate it is.
For an Extended Validation (EV) SSL certificate, Cardspace uses the O, L, S, C fields from the Subject field of certificate. These represent the Oraganization, Location, State and Country of the subject (the RP). Given that the CA has done some extended validation to verify the details of the subject, the subject gains the security that no other EV SSL certificate will have the same fields (unless issued to the same organization). This also grants the benefits that a organization can have a certificate re-issued with a new public/private key pair, and not affect the identities stored based on it.
For a regular SSL certificate, CardSpace uses the subject fields from all the certificate in the chain, all the way to the root certificate.public key of the certificate. This of course makes the PPIDs and key-pairs generated from that dependent on the issuance chain in the certificate. This may be a problem, if the certificate needs to be re-issued with a different chain later.
This is different than I had said in the past (where I said it was all calculated off the public-key of the RP’s certificate), I was apparently behind-the-times with this. Thanks Caleb. Dern newfangled-cryptography!
The net effect of this, is that the PPID and the public/private keypair are completely different for each and every relying party, even when the same personal card is used. This allows people to use the same personal card everywhere, and not worry about someone replaying their credentials.
So, I can rely on the PPID then?
What? Are you crazy!?
Anyone <glares at Caleb> could craft a token by hand that could contain the PPID. You can’t rely on that. … Alone.
In order to validate the identity of the person presenting the PPID, you have to also verify that they possess the private key which matches to the public key they presented to you with the PPID. The public key is delivered in the form of the Issuer’s public key in the SAML assertion. The token is signed by the Issuer’s private key, providing proof of possession of the private key. This signature can be cryptographically verified by the relying party.
So, you can rely on the PPID, if you verify the signature of the SAML assertion. And, you should store the public key, so that someone else can’t craft a token with someone elses PPID, and sign it. So, you have to check both the PPID and the public key, after verification.
Or, you can get lazy as heck.
The TokenProcessor code I wrote verifies the token, and since unverified tokens will throw an exception, this makes this pretty easy. As an additional step, the class provides a UniqueID field, which is the cryptographic hash of the issuer’s public key and a claim that is unique to that issuer (defaulting to the PPID).
So, I can rely on the UniqueID then?
As long as the signature is valid (and the Token object won’t get through the constructor otherwise), the UniqueID is what it says it is. Unique to that user. For the relationship that you have with that user. That user will have a different UniqueID than everyone else.
How about Managed Cards?
This works just as fine for Managed Cards as well. You can get the UniqueID for the user based off of the issuer’s public key and any field that the Issuer claims is unique in their database. An issuer may claim that any ID they issue tokens for will have a unique email address, so that the token they give to the relying party (via the user!) is their assertion that the user is who they (the IP) says they are.
Hang on here, something seems oddly familiar.
Uh-oh. My pappy used to remind me of two things about gettin’ into trouble. First, “Never slap a man who’s chewing tobacco.” .. that’s good advice you can’t afford to forget. The second is a little more on-topic, “If you find yourself in a hole, stop diggin’ .”
If you have two things which constitute credentials, only one of which is provin’ that the user has something that you don’t know, isn’t “PPID” and “Issuer’s public key” just like “Username” and “Password” ? … Why of course it is!. Except that the password isn’t sent. The proof of the possession of the password is sent by virtue of the token being signed by the private key. And the when public key is sent along with the signed token, the relying party is verifying the password.
Finally, you get to the point.
So, if’n yer lazy, you can add a column to your user database, call is UniqueID, and just verify the token, and get the UniqueID field, and look it up to log em in.
Or, if’n yer stubborn, you can put the PPID into the UserID field of your database, and the issuer public key into the password. I just hope that the password field in your database takes 2048 byte passwords. (heh-heh)… You may want to store the hash of the Issuer’s public key. Then you don’t have to touch the database, you don’t have to change anything, except for a tiny few lines of code to extract the “username” and “password” from the token.
And, now a word from the paranoid bull in the corner.
I’ve seen a few bits of Relying Party code pop up on the Internet, and I haven’t looked at many of them in detail. I will however grant you this word of advice.
IF YOU ARE WRITING CODE TO DECRYPT A SECURITY TOKEN AND ACCESS THE CLAIMS IN IT, YOU MUST VERIFY THE SIGNATURE ON THE TOKEN. DO NOT SKIP THIS STEP
I can not stress this enough. I’ve seen some people posting code on the net in different languages, but not performing the signature validation. That’s akin to asking for a username, but not checking the password and logging them in.
Y’all relax and enjoy.