Before getting into more details of how OpenID Association works, better we start with understanding how Diffie-Hellman key-exchange works.
Let's discuss this under the context of OpenID.
We have two parties interested in sharing a secret key through a non-secured media.
Let one of these be an OpenID Relying Party [RP] and the other be the OpenID Provider [OP].
So, RP and OP want to share a secret key between each other through a non-secured media.
Under Diffie-Hellman key-exchange, they need to do the following to establish a secret key.
Step 1: Both RP & OP agree on two values "g" and "p". The values of "g" and "p" can be known to any body - even other than the RP and the OP. Under the context of OpenID, these values are defined in the
OpenID Authentication Specification. Basically, "p" is a large prime number and "g" is a small number.
Step 2: RP selects a secret number, say "x" - which is typically a large number and compute another number, "X" - with the values of "g" and "p", where X = g^x mod p. Now RP can share "X" with OP [or anybody else] - which is the public key of RP - but it will still maintain "x" as a secret.
Step 3: OP will also select a secret number, say "y" - which is typically a large number and compute another number, "Y" - with the values of "g" and "p", where Y = g^y mod p. Now OP can share "Y" with RP [or anybody else] - which is the public key of OP - but it will still maintain "y" as a secret.
Step 4: Since the public key of OP - "Y" is known to anyone - RP can derive the Diffie-Hellman secret key [Kx] between OP and RP.
Kx = Y^x mod p
Although, "Y" is known publicly - "x" is kept as a secret at the RP - so nobody other than RP, can compute the value of Kx.
Step 5: Since the public key of RP - "X" is known to anyone - OP can derive the Diffie-Hellman secret key [Ky] between OP and RP.
Ky = X^y mod p
Although, "X" is known publicly - "y" is kept as a secret at the OP - so nobody other than OP, can compute the value of Ky.
Step 6: All set - we are done. Under the Diffie-Hellman key-exchange, Kx=Ky - so OP and RP shared a secret key between each other.
Okay - now we are done understanding Diffie-Hellman key-exchange. Let's start with understanding how OpenID Association works.
OpenID Authentication supports both a "smart mode" and "dumb mode" to accommodate Consumers of differing capabilities. A smart Consumer does a little more work at the beginning to save itself work later, but requires local caching of state information. A dumb Consumer is completely stateless, but requires extra an HTTP request.
Under "smart mode", it's recommended that a RP first submits an associate request (associate) to the End User's OP and requests a shared secret if the RP does not already have one cached.
So, the request for "Association" will take place after the "Discovery" - that is after the OP server url being discovered from a given OpenID.
The "Association" request is initiated by the RP using direct communication message called "associate" with an HTTP POST.
Let's discuss some of the important parameters included in an "associate" request.
1. openid.mode : This will have the value "associate" - indicates OP that this is an "associate" request.
2. openid.assoc_type : This defines the algorithm to be used to sign subsequent messages. OpenID 1.1 supported only HMAC-SHA1. HMAC-SHA256 was added in OpenID 2.0. In other words once an "association" being established between OP and RP - the same will be used for subsequent OpenID authentication requests between these OP and RP.
3. openid.session_type : This defines the method used to encrypt the association's MAC key in transit. MAC key is the shared key established between the OP and RP. Don't confuse this with the Diffie-Hellman shared secret. We basically use Diffie-Hellman shared secret to protect the MAC key [shared key] - will explain this more further later in this post.
openid.session_type can have any of the following values.
a. no-encryption
b. DH-SHA1
c. DH-SHA256 [Added in 2.0]
In a "no-encryption" association session, the OP sends the association MAC key in plain-text to the Relying Party. This makes it possible for an eavesdropper to intercept the key and forge messages to this Relying Party when not using transport layer encryption. Therefore, "no-encryption" association sessions MUST NOT be used unless the messages are using transport layer encryption.
The "DH-SHA1" and "DH-SHA256" association session types use Diffie-Hellman Key Exchange to securely transmit the shared secret - that is MAC key. In other words if you use "DH-SHA1" or "DH-SHA256" as the association session type - first OP and RP will derive a Diffie-Hellman shared secret, as explained in the beginning of this post, and will use that shared secret to encrypt the MAC key.
The following parameters are common to requests whose requested association session type is "DH-SHA1" or "DH-SHA256".
4. openid.dh_modulus : This is the value of "p" used in Diffie-Hellman key-exchange, where the default value defined in the spec.
5. openid.dh_gen : This is the value of "g" used in Diffie-Hellman key-exchange, where the default value defined in the spec.
6. openid.dh_consumer_public : This is the public key of RP for Diffie-Hellman key-exchange [X].
Once the OP receives the "associate" request - it will generate a MAC key and encrypt the MAC key [if "DH-SHA1" or "DH-SHA256" being used] with the Diffie-Hellman shared secret. OP will also share it's Diffie-Hellman public key with the RP through the response - so RP can derive the Diffie-Hellman shared secret from it and decrypt the MAC key.
Following are the important parameters is in the "associate" response.
1. assoc_handle : The association handle is used as a key to refer to this association in subsequent messages. assoc_handle will be used as key at both the OP and RP ends to cache the values associated with "associate" message.
2. expires_in : The lifetime, in seconds, of this association. The Relying Party MUST NOT use the association after this time has passed.
3. mac_key : The MAC key (shared secret) for this association, when "no-encryption" is used for session_type in the "associate" request.
4. dh_server_public : OP's Diffie-Hellman public key
5. enc_mac_key : The MAC key (shared secret), encrypted with the secret Diffie-Hellman value.
Once an "association" is established between the OP and the RP - the same "association" will be used for subsequent authentication requests. In other words, when a RP requests authentication for a given OpenID - it will include the already established assoc_handle in the authentication request.
Since the assoc_handle is passed to the OP - it will retrieve the cached MAC key using assoc_handle as a key, and will use that to "sign" the attributes before sending the response.