//----------------------------------------------------------------------- // // Copyright (c) Andrew Arnott. All rights reserved. // //----------------------------------------------------------------------- namespace DotNetOpenAuth.OpenId.Messages { using System; using System.Diagnostics.Contracts; using System.Security.Cryptography; using DotNetOpenAuth.Messaging; using DotNetOpenAuth.Messaging.Reflection; using DotNetOpenAuth.OpenId.Provider; using Org.Mentalis.Security.Cryptography; /// /// The successful Diffie-Hellman association response message. /// /// /// Association response messages are described in OpenID 2.0 section 8.2. This type covers section 8.2.3. /// internal class AssociateDiffieHellmanResponse : AssociateSuccessfulResponse { /// /// Initializes a new instance of the class. /// /// The OpenID version of the response message. /// The originating request. internal AssociateDiffieHellmanResponse(Version responseVersion, AssociateDiffieHellmanRequest originatingRequest) : base(responseVersion, originatingRequest) { } /// /// Gets or sets the Provider's Diffie-Hellman public key. /// /// btwoc(g ^ xb mod p) [MessagePart("dh_server_public", IsRequired = true, AllowEmpty = false)] internal byte[] DiffieHellmanServerPublic { get; set; } /// /// Gets or sets the MAC key (shared secret), encrypted with the secret Diffie-Hellman value. /// /// H(btwoc(g ^ (xa * xb) mod p)) XOR MAC key. H is either "SHA1" or "SHA256" depending on the session type. [MessagePart("enc_mac_key", IsRequired = true, AllowEmpty = false)] internal byte[] EncodedMacKey { get; set; } /// /// Creates the association at relying party side after the association response has been received. /// /// The original association request that was already sent and responded to. /// The newly created association. /// /// The resulting association is not added to the association store and must be done by the caller. /// protected override Association CreateAssociationAtRelyingParty(AssociateRequest request) { var diffieHellmanRequest = request as AssociateDiffieHellmanRequest; ErrorUtilities.VerifyArgument(diffieHellmanRequest != null, OpenIdStrings.DiffieHellmanAssociationRequired); HashAlgorithm hasher = DiffieHellmanUtilities.Lookup(Protocol, this.SessionType); byte[] associationSecret = DiffieHellmanUtilities.SHAHashXorSecret(hasher, diffieHellmanRequest.Algorithm, this.DiffieHellmanServerPublic, this.EncodedMacKey); Association association = HmacShaAssociation.Create(Protocol, this.AssociationType, this.AssociationHandle, associationSecret, TimeSpan.FromSeconds(this.ExpiresIn)); return association; } /// /// Creates the association at the provider side after the association request has been received. /// /// The association request. /// The OpenID Provider's association store or handle encoder. /// The security settings of the Provider. /// /// The newly created association. /// /// /// The response message is updated to include the details of the created association by this method, /// but the resulting association is not added to the association store and must be done by the caller. /// protected override Association CreateAssociationAtProvider(AssociateRequest request, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) { var diffieHellmanRequest = request as AssociateDiffieHellmanRequest; ErrorUtilities.VerifyInternal(diffieHellmanRequest != null, "Expected a DH request type."); this.SessionType = this.SessionType ?? request.SessionType; // Go ahead and create the association first, complete with its secret that we're about to share. Association association = HmacShaAssociation.Create(this.Protocol, this.AssociationType, AssociationRelyingPartyType.Smart, associationStore, securitySettings); // We now need to securely communicate the secret to the relying party using Diffie-Hellman. // We do this by performing a DH algorithm on the secret and setting a couple of properties // that will be transmitted to the Relying Party. The RP will perform an inverse operation // using its part of a DH secret in order to decrypt the shared secret we just invented // above when we created the association. using (DiffieHellman dh = new DiffieHellmanManaged( diffieHellmanRequest.DiffieHellmanModulus ?? AssociateDiffieHellmanRequest.DefaultMod, diffieHellmanRequest.DiffieHellmanGen ?? AssociateDiffieHellmanRequest.DefaultGen, AssociateDiffieHellmanRequest.DefaultX)) { HashAlgorithm hasher = DiffieHellmanUtilities.Lookup(this.Protocol, this.SessionType); this.DiffieHellmanServerPublic = DiffieHellmanUtilities.EnsurePositive(dh.CreateKeyExchange()); this.EncodedMacKey = DiffieHellmanUtilities.SHAHashXorSecret(hasher, dh, diffieHellmanRequest.DiffieHellmanConsumerPublic, association.SecretKey); } return association; } } }