Esempio n. 1
0
        private void StartSignature()
        {
            if (this.elementContainer.SourceSigningToken == null)
            {
                return;
            }

            // determine the key identifier clause to use for the source
            SecurityTokenReferenceStyle sourceSigningKeyReferenceStyle   = GetTokenReferenceStyle(this.signingTokenParameters);
            SecurityKeyIdentifierClause sourceSigningKeyIdentifierClause = this.signingTokenParameters.CreateKeyIdentifierClause(this.elementContainer.SourceSigningToken, sourceSigningKeyReferenceStyle);

            if (sourceSigningKeyIdentifierClause == null)
            {
                throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.TokenManagerCannotCreateTokenReference), this.Message);
            }

            SecurityToken signingToken;
            SecurityKeyIdentifierClause signingKeyIdentifierClause;

            // determine if a token needs to be derived
            if (this.signingTokenParameters.RequireDerivedKeys && !this.signingTokenParameters.HasAsymmetricKey)
            {
                string derivationAlgorithm         = this.AlgorithmSuite.GetSignatureKeyDerivationAlgorithm(this.elementContainer.SourceSigningToken, this.StandardsManager.MessageSecurityVersion.SecureConversationVersion);
                string expectedDerivationAlgorithm = SecurityUtils.GetKeyDerivationAlgorithm(this.StandardsManager.MessageSecurityVersion.SecureConversationVersion);
                if (derivationAlgorithm == expectedDerivationAlgorithm)
                {
                    DerivedKeySecurityToken derivedSigningToken = new DerivedKeySecurityToken(-1, 0, this.AlgorithmSuite.GetSignatureKeyDerivationLength(this.elementContainer.SourceSigningToken, this.StandardsManager.MessageSecurityVersion.SecureConversationVersion), null, DerivedKeySecurityToken.DefaultNonceLength, this.elementContainer.SourceSigningToken,
                                                                                              sourceSigningKeyIdentifierClause, derivationAlgorithm, GenerateId());
                    signingToken = this.elementContainer.DerivedSigningToken = derivedSigningToken;
                    signingKeyIdentifierClause = new LocalIdKeyIdentifierClause(signingToken.Id, signingToken.GetType());
                }
                else
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.Format(SR.UnsupportedCryptoAlgorithm, derivationAlgorithm)));
                }
            }
            else
            {
                signingToken = elementContainer.SourceSigningToken;
                signingKeyIdentifierClause = sourceSigningKeyIdentifierClause;
            }

            SecurityKeyIdentifier signingKeyIdentifier = new SecurityKeyIdentifier(signingKeyIdentifierClause);

            if (signatureConfirmationsToSend != null && signatureConfirmationsToSend.Count > 0)
            {
                ISecurityElement[] signatureConfirmationElements;
                signatureConfirmationElements = CreateSignatureConfirmationElements(signatureConfirmationsToSend);
                for (int i = 0; i < signatureConfirmationElements.Length; ++i)
                {
                    SendSecurityHeaderElement sigConfElement = new SendSecurityHeaderElement(signatureConfirmationElements[i].Id, signatureConfirmationElements[i]);
                    sigConfElement.MarkedForEncryption = signatureConfirmationsToSend.IsMarkedForEncryption;
                    this.elementContainer.AddSignatureConfirmation(sigConfElement);
                }
            }

            bool generateTargettablePrimarySignature = ((this.endorsingTokenParameters != null) || (this.signedEndorsingTokenParameters != null));

            this.StartPrimarySignatureCore(signingToken, signingKeyIdentifier, this.signatureParts, generateTargettablePrimarySignature);
        }
        public override bool MatchesKeyIdentifierClause(
            SecurityKeyIdentifierClause keyIdentifierClause)
        {
            LocalIdKeyIdentifierClause l = keyIdentifierClause
                                           as LocalIdKeyIdentifierClause;

            return(l != null && l.LocalId == Id);
        }
        bool MatchDirectReference(SecurityToken token, SecurityKeyIdentifierClause keyClause)
        {
            LocalIdKeyIdentifierClause localClause = keyClause as LocalIdKeyIdentifierClause;

            if (localClause == null)
            {
                return(false);
            }
            return(token.MatchesKeyIdentifierClause(localClause));
        }
        protected internal override bool MatchesKeyIdentifierClause(SecurityToken token, SecurityKeyIdentifierClause keyIdentifierClause, SecurityTokenReferenceStyle referenceStyle)
        {
            if (referenceStyle != SecurityTokenReferenceStyle.Internal)
            {
                return(false);
            }
            LocalIdKeyIdentifierClause clause = keyIdentifierClause as LocalIdKeyIdentifierClause;

            if (clause == null)
            {
                return(false);
            }
            return(clause.LocalId == token.Id);
        }
            bool TokenMatchesClause(SecurityToken token, SecurityKeyIdentifierClause clause)
            {
                if (token.MatchesKeyIdentifierClause(clause))
                {
                    return(true);
                }
                if (!match_local)
                {
                    return(false);
                }
                LocalIdKeyIdentifierClause l =
                    clause as LocalIdKeyIdentifierClause;

                return(l != null && l.Matches(token.Id, token.GetType()));
            }
Esempio n. 6
0
 internal static void SerializeLocalIdKeyIdentifierClause(XmlDictionaryWriter dictionaryWriter,
                                                          LocalIdKeyIdentifierClause localIdClause)
 {
     dictionaryWriter.WriteStartElement(XD_SecurityJan2004Dictionary_Prefix_Value,
                                        XD_SecurityJan2004Dictionary_SecurityTokenReference,
                                        XD_SecurityJan2004Dictionary_Namespace);
     dictionaryWriter.WriteStartElement(XD_SecurityJan2004Dictionary_Prefix_Value,
                                        XD_SecurityJan2004Dictionary_Reference,
                                        XD_SecurityJan2004Dictionary_Namespace);
     // tokenSerializer EmitBspRequiredAttributes is set to true
     dictionaryWriter.WriteAttributeString(XD_SecurityJan2004Dictionary_ValueType, null, X509TokenType);
     //end EmitBspRequiredAttributes
     dictionaryWriter.WriteAttributeString(XD_SecurityJan2004Dictionary_URI, null, "#" + localIdClause.LocalId);
     dictionaryWriter.WriteEndElement();
     dictionaryWriter.WriteEndElement();
 }
 void WriteLocalIdKeyIdentifierClause(
     XmlWriter w, LocalIdKeyIdentifierClause ic)
 {
     w.WriteStartElement("o", "SecurityTokenReference", Constants.WssNamespace);
     w.WriteStartElement("o", "Reference", Constants.WssNamespace);
     if (EmitBspRequiredAttributes && ic.OwnerType != null)
     {
         string vt = GetTokenTypeUri(ic.OwnerType);
         if (vt != null)
         {
             w.WriteAttributeString("ValueType", vt);
         }
     }
     w.WriteAttributeString("URI", "#" + ic.LocalId);
     w.WriteEndElement();
     w.WriteEndElement();
 }
 private void StartSignature()
 {
     if (this.elementContainer.SourceSigningToken != null)
     {
         SecurityToken sourceSigningToken;
         SecurityKeyIdentifierClause clause2;
         SecurityTokenReferenceStyle tokenReferenceStyle     = this.GetTokenReferenceStyle(this.signingTokenParameters);
         SecurityKeyIdentifierClause tokenToDeriveIdentifier = this.signingTokenParameters.CreateKeyIdentifierClause(this.elementContainer.SourceSigningToken, tokenReferenceStyle);
         if (tokenToDeriveIdentifier == null)
         {
             throw TraceUtility.ThrowHelperError(new MessageSecurityException(System.ServiceModel.SR.GetString("TokenManagerCannotCreateTokenReference")), base.Message);
         }
         if (this.signingTokenParameters.RequireDerivedKeys && !this.signingTokenParameters.HasAsymmetricKey)
         {
             string signatureKeyDerivationAlgorithm = base.AlgorithmSuite.GetSignatureKeyDerivationAlgorithm(this.elementContainer.SourceSigningToken, base.StandardsManager.MessageSecurityVersion.SecureConversationVersion);
             string keyDerivationAlgorithm          = System.ServiceModel.Security.SecurityUtils.GetKeyDerivationAlgorithm(base.StandardsManager.MessageSecurityVersion.SecureConversationVersion);
             if (signatureKeyDerivationAlgorithm != keyDerivationAlgorithm)
             {
                 throw System.ServiceModel.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(System.ServiceModel.SR.GetString("UnsupportedCryptoAlgorithm", new object[] { signatureKeyDerivationAlgorithm })));
             }
             DerivedKeySecurityToken token2 = new DerivedKeySecurityToken(-1, 0, base.AlgorithmSuite.GetSignatureKeyDerivationLength(this.elementContainer.SourceSigningToken, base.StandardsManager.MessageSecurityVersion.SecureConversationVersion), null, 0x10, this.elementContainer.SourceSigningToken, tokenToDeriveIdentifier, signatureKeyDerivationAlgorithm, this.GenerateId());
             sourceSigningToken = this.elementContainer.DerivedSigningToken = token2;
             clause2            = new LocalIdKeyIdentifierClause(sourceSigningToken.Id, sourceSigningToken.GetType());
         }
         else
         {
             sourceSigningToken = this.elementContainer.SourceSigningToken;
             clause2            = tokenToDeriveIdentifier;
         }
         SecurityKeyIdentifier identifier = new SecurityKeyIdentifier(new SecurityKeyIdentifierClause[] { clause2 });
         if ((this.signatureConfirmationsToSend != null) && (this.signatureConfirmationsToSend.Count > 0))
         {
             ISecurityElement[] elementArray = this.CreateSignatureConfirmationElements(this.signatureConfirmationsToSend);
             for (int i = 0; i < elementArray.Length; i++)
             {
                 SendSecurityHeaderElement confirmation = new SendSecurityHeaderElement(elementArray[i].Id, elementArray[i])
                 {
                     MarkedForEncryption = this.signatureConfirmationsToSend.IsMarkedForEncryption
                 };
                 this.elementContainer.AddSignatureConfirmation(confirmation);
             }
         }
         bool generateTargettablePrimarySignature = (this.endorsingTokenParameters != null) || (this.signedEndorsingTokenParameters != null);
         this.StartPrimarySignatureCore(sourceSigningToken, identifier, this.signatureParts, generateTargettablePrimarySignature);
     }
 }
        public void TryResolveToken()
        {
            SecurityTokenResolver r = GetResolver(true, new SecurityToken [0]);
            SecurityToken         token;

            Assert.IsFalse(r.TryResolveToken(new LocalIdKeyIdentifierClause("foo"), out token));

            UserNameSecurityToken userName =
                new UserNameSecurityToken("mono", "", "urn:foo");
            LocalIdKeyIdentifierClause kic =
                new LocalIdKeyIdentifierClause("urn:foo");

            r = GetResolver(true, new SecurityToken [] { userName });
            Assert.IsTrue(r.TryResolveToken(kic, out token));

            r = GetResolver(false, new SecurityToken [] { userName });
            Assert.IsFalse(r.TryResolveToken(kic, out token));
        }
 internal protected override bool MatchesKeyIdentifierClause(SecurityToken token, SecurityKeyIdentifierClause keyIdentifierClause, SecurityTokenReferenceStyle referenceStyle)
 {
     if (referenceStyle == SecurityTokenReferenceStyle.Internal)
     {
         LocalIdKeyIdentifierClause localClause = keyIdentifierClause as LocalIdKeyIdentifierClause;
         if (localClause == null)
         {
             return(false);
         }
         else
         {
             return(localClause.LocalId == token.Id);
         }
     }
     else
     {
         return(false);
     }
 }
        public override bool MatchesKeyIdentifierClause(SecurityKeyIdentifierClause keyIdentifierClause)
        {
            LocalIdKeyIdentifierClause lkic = keyIdentifierClause as LocalIdKeyIdentifierClause;

            if (lkic != null && lkic.LocalId == Id)
            {
                return(true);
            }

            InternalEncryptedKeyIdentifierClause khic = keyIdentifierClause as InternalEncryptedKeyIdentifierClause;

            if (keyhash == null)
            {
                keyhash = SHA1.Create().ComputeHash(wrapped_key);
            }
            if (khic != null && khic.Matches(keyhash))
            {
                return(true);
            }

            return(false);
        }
Esempio n. 12
0
        public void MatchesKeyIdentifierClause()
        {
            UniqueId                   id = new UniqueId();
            X509SecurityToken          t  = new X509SecurityToken(cert, id.ToString());
            LocalIdKeyIdentifierClause l  =
                new LocalIdKeyIdentifierClause(id.ToString());

            Assert.IsTrue(t.MatchesKeyIdentifierClause(l), "#1-1");

            l = new LocalIdKeyIdentifierClause("#" + id.ToString());
            Assert.IsFalse(t.MatchesKeyIdentifierClause(l), "#1-2");

            X509ThumbprintKeyIdentifierClause h =
                new X509ThumbprintKeyIdentifierClause(cert);

            Assert.IsTrue(t.MatchesKeyIdentifierClause(h), "#2-1");

            h = new X509ThumbprintKeyIdentifierClause(cert2);
            Assert.IsFalse(t.MatchesKeyIdentifierClause(h), "#2-2");

            X509IssuerSerialKeyIdentifierClause i =
                new X509IssuerSerialKeyIdentifierClause(cert);

            Assert.IsTrue(t.MatchesKeyIdentifierClause(i), "#3-1");

            i = new X509IssuerSerialKeyIdentifierClause(cert2);
            Assert.IsFalse(t.MatchesKeyIdentifierClause(i), "#3-2");

            X509RawDataKeyIdentifierClause s =
                new X509RawDataKeyIdentifierClause(cert);

            Assert.IsTrue(t.MatchesKeyIdentifierClause(s), "#4-1");

            s = new X509RawDataKeyIdentifierClause(cert2);
            Assert.IsFalse(t.MatchesKeyIdentifierClause(s), "#4-2");
        }
 private void StartEncryption()
 {
     if (this.elementContainer.SourceEncryptionToken != null)
     {
         SecurityToken sourceEncryptionToken;
         SecurityKeyIdentifierClause clause2;
         SecurityKeyIdentifierClause clause3;
         SecurityKeyIdentifier       identifier;
         SecurityTokenReferenceStyle tokenReferenceStyle = this.GetTokenReferenceStyle(this.encryptingTokenParameters);
         bool flag = tokenReferenceStyle == SecurityTokenReferenceStyle.Internal;
         SecurityKeyIdentifierClause clause = this.encryptingTokenParameters.CreateKeyIdentifierClause(this.elementContainer.SourceEncryptionToken, tokenReferenceStyle);
         if (clause == null)
         {
             throw TraceUtility.ThrowHelperError(new MessageSecurityException(System.ServiceModel.SR.GetString("TokenManagerCannotCreateTokenReference")), base.Message);
         }
         if (!System.ServiceModel.Security.SecurityUtils.HasSymmetricSecurityKey(this.elementContainer.SourceEncryptionToken))
         {
             string str;
             XmlDictionaryString str2;
             int keyLength = Math.Max(0x80, base.AlgorithmSuite.DefaultSymmetricKeyLength);
             System.ServiceModel.Security.CryptoHelper.ValidateSymmetricKeyLength(keyLength, base.AlgorithmSuite);
             byte[] buffer = new byte[keyLength / 8];
             System.ServiceModel.Security.CryptoHelper.FillRandomBytes(buffer);
             base.AlgorithmSuite.GetKeyWrapAlgorithm(this.elementContainer.SourceEncryptionToken, out str, out str2);
             WrappedKeySecurityToken token2 = new WrappedKeySecurityToken(this.GenerateId(), buffer, str, str2, this.elementContainer.SourceEncryptionToken, new SecurityKeyIdentifier(new SecurityKeyIdentifierClause[] { clause }));
             this.elementContainer.WrappedEncryptionToken = token2;
             sourceEncryptionToken = token2;
             clause2 = new LocalIdKeyIdentifierClause(token2.Id, token2.GetType());
             flag    = true;
         }
         else
         {
             sourceEncryptionToken = this.elementContainer.SourceEncryptionToken;
             clause2 = clause;
         }
         if (this.encryptingTokenParameters.RequireDerivedKeys)
         {
             string encryptionKeyDerivationAlgorithm = base.AlgorithmSuite.GetEncryptionKeyDerivationAlgorithm(sourceEncryptionToken, base.StandardsManager.MessageSecurityVersion.SecureConversationVersion);
             string keyDerivationAlgorithm           = System.ServiceModel.Security.SecurityUtils.GetKeyDerivationAlgorithm(base.StandardsManager.MessageSecurityVersion.SecureConversationVersion);
             if (encryptionKeyDerivationAlgorithm != keyDerivationAlgorithm)
             {
                 throw System.ServiceModel.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(System.ServiceModel.SR.GetString("UnsupportedCryptoAlgorithm", new object[] { encryptionKeyDerivationAlgorithm })));
             }
             DerivedKeySecurityToken token3 = new DerivedKeySecurityToken(-1, 0, base.AlgorithmSuite.GetEncryptionKeyDerivationLength(sourceEncryptionToken, base.StandardsManager.MessageSecurityVersion.SecureConversationVersion), null, 0x10, sourceEncryptionToken, clause2, encryptionKeyDerivationAlgorithm, this.GenerateId());
             this.encryptingToken = this.elementContainer.DerivedEncryptionToken = token3;
             clause3 = new LocalIdKeyIdentifierClause(token3.Id, token3.GetType());
         }
         else
         {
             this.encryptingToken = sourceEncryptionToken;
             clause3 = clause2;
         }
         this.skipKeyInfoForEncryption = ((flag && base.EncryptedKeyContainsReferenceList) && (this.encryptingToken is WrappedKeySecurityToken)) && this.signThenEncrypt;
         if (this.skipKeyInfoForEncryption)
         {
             identifier = null;
         }
         else
         {
             identifier = new SecurityKeyIdentifier(new SecurityKeyIdentifierClause[] { clause3 });
         }
         this.StartEncryptionCore(this.encryptingToken, identifier);
     }
 }
Esempio n. 14
0
 private void SignWithSupportingTokens()
 {
     SecurityToken[] endorsingTokens = ElementContainer.GetEndorsingSupportingTokens();
     if (endorsingTokens != null)
     {
         for (int i = 0; i < endorsingTokens.Length; ++i)
         {
             SecurityToken source = endorsingTokens[i];
             SecurityKeyIdentifierClause sourceKeyClause = _endorsingTokenParameters[i].CreateKeyIdentifierClause(source, GetTokenReferenceStyle(_endorsingTokenParameters[i]));
             if (sourceKeyClause == null)
             {
                 throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.Format(SR.TokenManagerCannotCreateTokenReference)), Message);
             }
             SecurityToken signingToken;
             SecurityKeyIdentifierClause signingKeyClause;
             if (_endorsingTokenParameters[i].RequireDerivedKeys && !_endorsingTokenParameters[i].HasAsymmetricKey)
             {
                 string derivationAlgorithm  = SecurityUtils.GetKeyDerivationAlgorithm(StandardsManager.MessageSecurityVersion.SecureConversationVersion);
                 DerivedKeySecurityToken dkt = new DerivedKeySecurityToken(-1, 0,
                                                                           AlgorithmSuite.GetSignatureKeyDerivationLength(source, StandardsManager.MessageSecurityVersion.SecureConversationVersion), null,
                                                                           DerivedKeySecurityToken.DefaultNonceLength, source, sourceKeyClause, derivationAlgorithm, GenerateId());
                 signingToken     = dkt;
                 signingKeyClause = new LocalIdKeyIdentifierClause(dkt.Id, dkt.GetType());
                 ElementContainer.AddEndorsingDerivedSupportingToken(dkt);
             }
             else
             {
                 signingToken     = source;
                 signingKeyClause = sourceKeyClause;
             }
             SignWithSupportingToken(signingToken, signingKeyClause);
         }
     }
     SecurityToken[] signedEndorsingSupportingTokens = ElementContainer.GetSignedEndorsingSupportingTokens();
     if (signedEndorsingSupportingTokens != null)
     {
         for (int i = 0; i < signedEndorsingSupportingTokens.Length; ++i)
         {
             SecurityToken source = signedEndorsingSupportingTokens[i];
             SecurityKeyIdentifierClause sourceKeyClause = _signedEndorsingTokenParameters[i].CreateKeyIdentifierClause(source, GetTokenReferenceStyle(_signedEndorsingTokenParameters[i]));
             if (sourceKeyClause == null)
             {
                 throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.Format(SR.TokenManagerCannotCreateTokenReference)), Message);
             }
             SecurityToken signingToken;
             SecurityKeyIdentifierClause signingKeyClause;
             if (_signedEndorsingTokenParameters[i].RequireDerivedKeys && !_signedEndorsingTokenParameters[i].HasAsymmetricKey)
             {
                 string derivationAlgorithm  = SecurityUtils.GetKeyDerivationAlgorithm(StandardsManager.MessageSecurityVersion.SecureConversationVersion);
                 DerivedKeySecurityToken dkt = new DerivedKeySecurityToken(-1, 0,
                                                                           AlgorithmSuite.GetSignatureKeyDerivationLength(source, StandardsManager.MessageSecurityVersion.SecureConversationVersion), null,
                                                                           DerivedKeySecurityToken.DefaultNonceLength, source, sourceKeyClause, derivationAlgorithm, GenerateId());
                 signingToken     = dkt;
                 signingKeyClause = new LocalIdKeyIdentifierClause(dkt.Id, dkt.GetType());
                 ElementContainer.AddSignedEndorsingDerivedSupportingToken(dkt);
             }
             else
             {
                 signingToken     = source;
                 signingKeyClause = sourceKeyClause;
             }
             SignWithSupportingToken(signingToken, signingKeyClause);
         }
     }
 }
        private async Task <string> SerializeIdentityTokenAsync(
            ClaimsIdentity identity, AuthenticationProperties properties,
            OpenIdConnectMessage request, OpenIdConnectMessage response)
        {
            // properties.IssuedUtc and properties.ExpiresUtc
            // should always be preferred when explicitly set.
            if (properties.IssuedUtc == null)
            {
                properties.IssuedUtc = Options.SystemClock.UtcNow;
            }

            if (properties.ExpiresUtc == null)
            {
                properties.ExpiresUtc = properties.IssuedUtc + Options.IdentityTokenLifetime;
            }

            // Replace the identity by a new one containing only the filtered claims.
            // Actors identities are also filtered (delegation scenarios).
            identity = identity.Clone(claim => {
                // Never exclude ClaimTypes.NameIdentifier.
                if (string.Equals(claim.Type, ClaimTypes.NameIdentifier, StringComparison.OrdinalIgnoreCase))
                {
                    return(true);
                }

                // Claims whose destination is not explicitly referenced or doesn't
                // contain "id_token" are not included in the identity token.
                return(claim.HasDestination(OpenIdConnectConstants.Destinations.IdentityToken));
            });

            // Create a new ticket containing the updated properties and the filtered identity.
            var ticket = new AuthenticationTicket(identity, properties);

            ticket.SetUsage(OpenIdConnectConstants.Usages.IdToken);

            // Associate a random identifier with the identity token.
            ticket.SetTicketId(Guid.NewGuid().ToString());

            // By default, add the client_id to the list of the
            // presenters allowed to use the identity token.
            if (!string.IsNullOrEmpty(request.ClientId))
            {
                ticket.SetAudiences(request.ClientId);
                ticket.SetPresenters(request.ClientId);
            }

            var notification = new SerializeIdentityTokenContext(Context, Options, request, response, ticket)
            {
                Issuer = Context.GetIssuer(Options),
                SecurityTokenHandler = Options.IdentityTokenHandler,
                SigningCredentials   = Options.SigningCredentials.FirstOrDefault()
            };

            await Options.Provider.SerializeIdentityToken(notification);

            if (!string.IsNullOrEmpty(notification.IdentityToken))
            {
                return(notification.IdentityToken);
            }

            if (notification.SecurityTokenHandler == null)
            {
                return(null);
            }

            if (!identity.HasClaim(claim => claim.Type == OpenIdConnectConstants.Claims.Subject) &&
                !identity.HasClaim(claim => claim.Type == ClaimTypes.NameIdentifier))
            {
                throw new InvalidOperationException("A unique identifier cannot be found to generate a 'sub' claim: " +
                                                    "make sure to add a 'ClaimTypes.NameIdentifier' claim.");
            }

            // Store the unique subject identifier as a claim.
            if (!identity.HasClaim(claim => claim.Type == OpenIdConnectConstants.Claims.Subject))
            {
                identity.AddClaim(OpenIdConnectConstants.Claims.Subject, identity.GetClaim(ClaimTypes.NameIdentifier));
            }

            // Remove the ClaimTypes.NameIdentifier claims to avoid getting duplicate claims.
            // Note: the "sub" claim is automatically mapped by JwtSecurityTokenHandler
            // to ClaimTypes.NameIdentifier when validating a JWT token.
            // Note: make sure to call ToArray() to avoid an InvalidOperationException
            // on old versions of Mono, where FindAll() is implemented using an iterator.
            foreach (var claim in identity.FindAll(ClaimTypes.NameIdentifier).ToArray())
            {
                identity.RemoveClaim(claim);
            }

            // Store the "unique_id" property as a claim.
            ticket.Identity.AddClaim(OpenIdConnectConstants.Claims.JwtId, ticket.GetTicketId());

            // Store the "usage" property as a claim.
            ticket.Identity.AddClaim(OpenIdConnectConstants.Claims.Usage, ticket.GetUsage());

            // If the ticket is marked as confidential, add a new
            // "confidential" claim in the security token.
            if (ticket.IsConfidential())
            {
                ticket.Identity.AddClaim(new Claim(OpenIdConnectConstants.Claims.Confidential, "true", ClaimValueTypes.Boolean));
            }

            // Store the audiences as claims.
            foreach (var audience in ticket.GetAudiences())
            {
                ticket.Identity.AddClaim(OpenIdConnectConstants.Claims.Audience, audience);
            }

            // If a nonce was present in the authorization request, it MUST
            // be included in the id_token generated by the token endpoint.
            // See http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
            var nonce = request.Nonce;

            if (request.IsAuthorizationCodeGrantType())
            {
                // Restore the nonce stored in the authentication
                // ticket extracted from the authorization code.
                nonce = ticket.GetNonce();
            }

            if (!string.IsNullOrEmpty(nonce))
            {
                ticket.Identity.AddClaim(OpenIdConnectConstants.Claims.Nonce, nonce);
            }

            if (!string.IsNullOrEmpty(response.Code))
            {
                using (var algorithm = HashAlgorithm.Create(notification.SigningCredentials.DigestAlgorithm)) {
                    // Create the c_hash using the authorization code returned by SerializeAuthorizationCodeAsync.
                    var hash = algorithm.ComputeHash(Encoding.ASCII.GetBytes(response.Code));

                    // Note: only the left-most half of the hash of the octets is used.
                    // See http://openid.net/specs/openid-connect-core-1_0.html#HybridIDToken
                    ticket.Identity.AddClaim(OpenIdConnectConstants.Claims.CodeHash,
                                             Base64UrlEncoder.Encode(hash, 0, hash.Length / 2));
                }
            }

            if (!string.IsNullOrEmpty(response.AccessToken))
            {
                using (var algorithm = HashAlgorithm.Create(notification.SigningCredentials.DigestAlgorithm)) {
                    // Create the at_hash using the access token returned by SerializeAccessTokenAsync.
                    var hash = algorithm.ComputeHash(Encoding.ASCII.GetBytes(response.AccessToken));

                    // Note: only the left-most half of the hash of the octets is used.
                    // See http://openid.net/specs/openid-connect-core-1_0.html#CodeIDToken
                    ticket.Identity.AddClaim(OpenIdConnectConstants.Claims.AccessTokenHash,
                                             Base64UrlEncoder.Encode(hash, 0, hash.Length / 2));
                }
            }

            // Extract the presenters from the authentication ticket.
            var presenters = ticket.GetPresenters().ToArray();

            switch (presenters.Length)
            {
            case 0: break;

            case 1:
                identity.AddClaim(OpenIdConnectConstants.Claims.AuthorizedParty, presenters[0]);
                break;

            default:
                Options.Logger.LogWarning("Multiple presenters have been associated with the identity token " +
                                          "but the JWT format only accepts single values.");

                // Only add the first authorized party.
                identity.AddClaim(OpenIdConnectConstants.Claims.AuthorizedParty, presenters[0]);
                break;
            }

            var token = notification.SecurityTokenHandler.CreateToken(
                subject: ticket.Identity,
                issuer: notification.Issuer,
                signingCredentials: notification.SigningCredentials,
                notBefore: ticket.Properties.IssuedUtc.Value.UtcDateTime,
                expires: ticket.Properties.ExpiresUtc.Value.UtcDateTime);

            token.Payload[OpenIdConnectConstants.Claims.IssuedAt] =
                EpochTime.GetIntDate(ticket.Properties.IssuedUtc.Value.UtcDateTime);

            // Try to extract a key identifier from the signing credentials
            // and add the "kid" property to the JWT header if applicable.
            LocalIdKeyIdentifierClause clause = null;

            if (notification.SigningCredentials?.SigningKeyIdentifier != null &&
                notification.SigningCredentials.SigningKeyIdentifier.TryFind(out clause))
            {
                token.Header[JwtHeaderParameterNames.Kid] = clause.LocalId;
            }

            return(notification.SecurityTokenHandler.WriteToken(token));
        }
        private async Task <string> SerializeAccessTokenAsync(
            ClaimsIdentity identity, AuthenticationProperties properties,
            OpenIdConnectMessage request, OpenIdConnectMessage response)
        {
            // properties.IssuedUtc and properties.ExpiresUtc
            // should always be preferred when explicitly set.
            if (properties.IssuedUtc == null)
            {
                properties.IssuedUtc = Options.SystemClock.UtcNow;
            }

            if (properties.ExpiresUtc == null)
            {
                properties.ExpiresUtc = properties.IssuedUtc + Options.AccessTokenLifetime;
            }

            // Create a new identity containing only the filtered claims.
            // Actors identities are also filtered (delegation scenarios).
            identity = identity.Clone(claim => {
                // Never exclude ClaimTypes.NameIdentifier.
                if (string.Equals(claim.Type, ClaimTypes.NameIdentifier, StringComparison.OrdinalIgnoreCase))
                {
                    return(true);
                }

                // Claims whose destination is not explicitly referenced or doesn't
                // contain "access_token" are not included in the access token.
                return(claim.HasDestination(OpenIdConnectConstants.Destinations.AccessToken));
            });

            // Create a new ticket containing the updated properties and the filtered identity.
            var ticket = new AuthenticationTicket(identity, properties);

            ticket.SetUsage(OpenIdConnectConstants.Usages.AccessToken);
            ticket.SetAudiences(ticket.GetResources());

            // Associate a random identifier with the access token.
            ticket.SetTicketId(Guid.NewGuid().ToString());

            // By default, add the client_id to the list of the
            // presenters allowed to use the access token.
            if (!string.IsNullOrEmpty(request.ClientId))
            {
                ticket.SetPresenters(request.ClientId);
            }

            var notification = new SerializeAccessTokenContext(Context, Options, request, response, ticket)
            {
                DataFormat           = Options.AccessTokenFormat,
                Issuer               = Context.GetIssuer(Options),
                SecurityTokenHandler = Options.AccessTokenHandler,
                SigningCredentials   = Options.SigningCredentials.FirstOrDefault()
            };

            await Options.Provider.SerializeAccessToken(notification);

            if (!string.IsNullOrEmpty(notification.AccessToken))
            {
                return(notification.AccessToken);
            }

            if (notification.SecurityTokenHandler == null)
            {
                return(notification.DataFormat?.Protect(ticket));
            }

            // Store the "unique_id" property as a claim.
            ticket.Identity.AddClaim(notification.SecurityTokenHandler is JwtSecurityTokenHandler ?
                                     OpenIdConnectConstants.Claims.JwtId :
                                     OpenIdConnectConstants.Claims.TokenId, ticket.GetTicketId());

            // Store the "usage" property as a claim.
            ticket.Identity.AddClaim(OpenIdConnectConstants.Claims.Usage, ticket.GetUsage());

            // If the ticket is marked as confidential, add a new
            // "confidential" claim in the security token.
            if (ticket.IsConfidential())
            {
                ticket.Identity.AddClaim(new Claim(OpenIdConnectConstants.Claims.Confidential, "true", ClaimValueTypes.Boolean));
            }

            // Create a new claim per scope item, that will result
            // in a "scope" array being added in the access token.
            foreach (var scope in ticket.GetScopes())
            {
                ticket.Identity.AddClaim(OpenIdConnectConstants.Claims.Scope, scope);
            }

            var handler = notification.SecurityTokenHandler as JwtSecurityTokenHandler;

            if (handler != null)
            {
                // Note: when used as an access token, a JWT token doesn't have to expose a "sub" claim
                // but the name identifier claim is used as a substitute when it has been explicitly added.
                // See https://tools.ietf.org/html/rfc7519#section-4.1.2
                var subject = identity.FindFirst(OpenIdConnectConstants.Claims.Subject);
                if (subject == null)
                {
                    var identifier = identity.FindFirst(ClaimTypes.NameIdentifier);
                    if (identifier != null)
                    {
                        identity.AddClaim(OpenIdConnectConstants.Claims.Subject, identifier.Value);
                    }
                }

                // Remove the ClaimTypes.NameIdentifier claims to avoid getting duplicate claims.
                // Note: the "sub" claim is automatically mapped by JwtSecurityTokenHandler
                // to ClaimTypes.NameIdentifier when validating a JWT token.
                // Note: make sure to call ToArray() to avoid an InvalidOperationException
                // on old versions of Mono, where FindAll() is implemented using an iterator.
                foreach (var claim in ticket.Identity.FindAll(ClaimTypes.NameIdentifier).ToArray())
                {
                    ticket.Identity.RemoveClaim(claim);
                }

                // Store the audiences as claims.
                foreach (var audience in ticket.GetAudiences())
                {
                    ticket.Identity.AddClaim(OpenIdConnectConstants.Claims.Audience, audience);
                }

                // Extract the presenters from the authentication ticket.
                var presenters = ticket.GetPresenters().ToArray();

                switch (presenters.Length)
                {
                case 0: break;

                case 1:
                    identity.AddClaim(OpenIdConnectConstants.Claims.AuthorizedParty, presenters[0]);
                    break;

                default:
                    Options.Logger.LogWarning("Multiple presenters have been associated with the access token " +
                                              "but the JWT format only accepts single values.");

                    // Only add the first authorized party.
                    identity.AddClaim(OpenIdConnectConstants.Claims.AuthorizedParty, presenters[0]);
                    break;
                }

                var token = handler.CreateToken(
                    subject: ticket.Identity,
                    issuer: notification.Issuer,
                    signingCredentials: notification.SigningCredentials,
                    notBefore: ticket.Properties.IssuedUtc.Value.UtcDateTime,
                    expires: ticket.Properties.ExpiresUtc.Value.UtcDateTime);

                token.Payload[OpenIdConnectConstants.Claims.IssuedAt] =
                    EpochTime.GetIntDate(ticket.Properties.IssuedUtc.Value.UtcDateTime);

                // Try to extract a key identifier from the signing credentials
                // and add the "kid" property to the JWT header if applicable.
                LocalIdKeyIdentifierClause clause = null;
                if (notification.SigningCredentials?.SigningKeyIdentifier != null &&
                    notification.SigningCredentials.SigningKeyIdentifier.TryFind(out clause))
                {
                    token.Header[JwtHeaderParameterNames.Kid] = clause.LocalId;
                }

                return(handler.WriteToken(token));
            }

            else
            {
                var descriptor = new SecurityTokenDescriptor {
                    Subject               = ticket.Identity,
                    AppliesToAddress      = notification.Audiences.ElementAtOrDefault(0),
                    TokenIssuerName       = notification.Issuer,
                    EncryptingCredentials = notification.EncryptingCredentials,
                    SigningCredentials    = notification.SigningCredentials,
                    Lifetime              = new Lifetime(
                        notification.Ticket.Properties.IssuedUtc.Value.UtcDateTime,
                        notification.Ticket.Properties.ExpiresUtc.Value.UtcDateTime)
                };

                // When the encrypting credentials use an asymmetric key, replace them by a
                // EncryptedKeyEncryptingCredentials instance to generate a symmetric key.
                if (descriptor.EncryptingCredentials != null &&
                    descriptor.EncryptingCredentials.SecurityKey is AsymmetricSecurityKey)
                {
                    // Note: EncryptedKeyEncryptingCredentials automatically generates an in-memory key
                    // that will be encrypted using the original credentials and added to the resulting token
                    // if the security token handler fully supports token encryption (e.g SAML or SAML2).
                    descriptor.EncryptingCredentials = new EncryptedKeyEncryptingCredentials(
                        wrappingCredentials: notification.EncryptingCredentials, keySizeInBits: 256,
                        encryptionAlgorithm: SecurityAlgorithms.Aes256Encryption);
                }

                var token = notification.SecurityTokenHandler.CreateToken(descriptor);

                // Note: the security token is manually serialized to prevent
                // an exception from being thrown if the handler doesn't implement
                // the SecurityTokenHandler.WriteToken overload returning a string.
                var builder = new StringBuilder();
                using (var writer = XmlWriter.Create(builder, new XmlWriterSettings {
                    Encoding = new UTF8Encoding(false), OmitXmlDeclaration = true
                })) {
                    notification.SecurityTokenHandler.WriteToken(writer, token);
                }

                return(builder.ToString());
            }
        }
Esempio n. 17
0
        private void StartEncryption()
        {
            if (ElementContainer.SourceEncryptionToken == null)
            {
                return;
            }
            // determine the key identifier clause to use for the source
            SecurityTokenReferenceStyle sourceEncryptingKeyReferenceStyle = GetTokenReferenceStyle(_encryptingTokenParameters);
            bool encryptionTokenSerialized = sourceEncryptingKeyReferenceStyle == SecurityTokenReferenceStyle.Internal;
            SecurityKeyIdentifierClause sourceEncryptingKeyIdentifierClause = _encryptingTokenParameters.CreateKeyIdentifierClause(ElementContainer.SourceEncryptionToken, sourceEncryptingKeyReferenceStyle);

            if (sourceEncryptingKeyIdentifierClause == null)
            {
                throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.TokenManagerCannotCreateTokenReference), Message);
            }
            SecurityToken sourceToken;
            SecurityKeyIdentifierClause sourceTokenIdentifierClause;

            // if the source token cannot do symmetric crypto, create a wrapped key
            if (!SecurityUtils.HasSymmetricSecurityKey(ElementContainer.SourceEncryptionToken))
            {
                int keyLength = Math.Max(128, AlgorithmSuite.DefaultSymmetricKeyLength);
                CryptoHelper.ValidateSymmetricKeyLength(keyLength, AlgorithmSuite);
                byte[] key = new byte[keyLength / 8];
                CryptoHelper.FillRandomBytes(key);
                AlgorithmSuite.GetKeyWrapAlgorithm(ElementContainer.SourceEncryptionToken, out string keyWrapAlgorithm, out XmlDictionaryString keyWrapAlgorithmDictionaryString);
                WrappedKeySecurityToken wrappedKey = new WrappedKeySecurityToken(GenerateId(), key, keyWrapAlgorithm, keyWrapAlgorithmDictionaryString,
                                                                                 ElementContainer.SourceEncryptionToken, new SecurityKeyIdentifier(sourceEncryptingKeyIdentifierClause));
                ElementContainer.WrappedEncryptionToken = wrappedKey;
                sourceToken = wrappedKey;
                sourceTokenIdentifierClause = new LocalIdKeyIdentifierClause(wrappedKey.Id, wrappedKey.GetType());
                encryptionTokenSerialized   = true;
            }
            else
            {
                sourceToken = ElementContainer.SourceEncryptionToken;
                sourceTokenIdentifierClause = sourceEncryptingKeyIdentifierClause;
            }

            // determine if a key needs to be derived
            SecurityKeyIdentifierClause encryptingKeyIdentifierClause;

            // determine if a token needs to be derived
            if (_encryptingTokenParameters.RequireDerivedKeys)
            {
                string derivationAlgorithm         = AlgorithmSuite.GetEncryptionKeyDerivationAlgorithm(sourceToken, StandardsManager.MessageSecurityVersion.SecureConversationVersion);
                string expectedDerivationAlgorithm = SecurityUtils.GetKeyDerivationAlgorithm(StandardsManager.MessageSecurityVersion.SecureConversationVersion);
                if (derivationAlgorithm == expectedDerivationAlgorithm)
                {
                    DerivedKeySecurityToken derivedEncryptingToken = new DerivedKeySecurityToken(-1, 0,
                                                                                                 AlgorithmSuite.GetEncryptionKeyDerivationLength(sourceToken, StandardsManager.MessageSecurityVersion.SecureConversationVersion), null, DerivedKeySecurityToken.DefaultNonceLength, sourceToken, sourceTokenIdentifierClause, derivationAlgorithm, GenerateId());
                    _encryptingToken = ElementContainer.DerivedEncryptionToken = derivedEncryptingToken;
                    encryptingKeyIdentifierClause = new LocalIdKeyIdentifierClause(derivedEncryptingToken.Id, derivedEncryptingToken.GetType());
                }
                else
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.Format(SR.UnsupportedCryptoAlgorithm, derivationAlgorithm)));
                }
            }
            else
            {
                _encryptingToken = sourceToken;
                encryptingKeyIdentifierClause = sourceTokenIdentifierClause;
            }

            _skipKeyInfoForEncryption = encryptionTokenSerialized && EncryptedKeyContainsReferenceList && (_encryptingToken is WrappedKeySecurityToken) && _signThenEncrypt;
            SecurityKeyIdentifier identifier;

            if (_skipKeyInfoForEncryption)
            {
                identifier = null;
            }
            else
            {
                identifier = new SecurityKeyIdentifier(encryptingKeyIdentifierClause);
            }

            StartEncryptionCore(_encryptingToken, identifier);
        }
        SecurityKeyIdentifierClause ReadSecurityTokenReference(XmlReader reader)
        {
            reader.ReadStartElement();
            reader.MoveToContent();
            if (reader.NamespaceURI == SignedXml.XmlDsigNamespaceUrl)
            {
                KeyInfoX509Data x509 = new KeyInfoX509Data();
                x509.LoadXml(new XmlDocument().ReadNode(reader) as XmlElement);
                if (x509.IssuerSerials.Count == 0)
                {
                    throw new XmlException("'X509IssuerSerial' element is expected inside 'X509Data' element");
                }
                X509IssuerSerial s = (X509IssuerSerial)x509.IssuerSerials [0];
                reader.MoveToContent();
                reader.ReadEndElement();
                return(new X509IssuerSerialKeyIdentifierClause(s.IssuerName, s.SerialNumber));
            }
            if (reader.NamespaceURI != Constants.WssNamespace)
            {
                throw new XmlException(String.Format("Unexpected SecurityTokenReference content: expected local name 'Reference' and namespace URI '{0}' but found local name '{1}' and namespace '{2}'.", Constants.WssNamespace, reader.LocalName, reader.NamespaceURI));
            }

            switch (reader.LocalName)
            {
            case "Reference":
                Type ownerType = null;
                // FIXME: there could be more token types.
                if (reader.MoveToAttribute("ValueType"))
                {
                    switch (reader.Value)
                    {
                    case Constants.WSSEncryptedKeyToken:
                        ownerType = typeof(WrappedKeySecurityToken);
                        break;

                    case Constants.WSSX509Token:
                        ownerType = typeof(X509SecurityToken);
                        break;

                    case Constants.WsscContextToken:
                        ownerType = typeof(SecurityContextSecurityToken);
                        break;

                    default:
                        throw new XmlException(String.Format("Unexpected ValueType in 'Reference' element: '{0}'", reader.Value));
                    }
                }
                reader.MoveToElement();
                string uri = reader.GetAttribute("URI");
                if (String.IsNullOrEmpty(uri))
                {
                    uri = "#";
                }
                SecurityKeyIdentifierClause ic = null;
                if (ownerType == typeof(SecurityContextSecurityToken) && uri [0] != '#')
                {
                    // FIXME: Generation?
                    ic = new SecurityContextKeyIdentifierClause(new UniqueId(uri));
                }
                else
                {
                    ic = new LocalIdKeyIdentifierClause(uri.Substring(1), ownerType);
                }
                reader.Skip();
                reader.MoveToContent();
                reader.ReadEndElement();
                return(ic);

            case "KeyIdentifier":
                string valueType = reader.GetAttribute("ValueType");
                string value     = reader.ReadElementContentAsString();
                reader.MoveToContent();
                reader.ReadEndElement();                  // consume </Reference>
                switch (valueType)
                {
                case Constants.WssKeyIdentifierX509Thumbptint:
                    return(new X509ThumbprintKeyIdentifierClause(Convert.FromBase64String(value)));

                case Constants.WssKeyIdentifierEncryptedKey:
                    return(new InternalEncryptedKeyIdentifierClause(Convert.FromBase64String(value)));

                case Constants.WssKeyIdentifierSamlAssertion:
                    return(new SamlAssertionKeyIdentifierClause(value));

                default:
                    // It is kinda weird but it throws XmlException here ...
                    throw new XmlException(String.Format("KeyIdentifier type '{0}' is not supported in WSSecurityTokenSerializer.", valueType));
                }

            default:
                throw new XmlException(String.Format("Unexpected SecurityTokenReference content: expected local name 'Reference' and namespace URI '{0}' but found local name '{1}' and namespace '{2}'.", Constants.WssNamespace, reader.LocalName, reader.NamespaceURI));
            }
        }
Esempio n. 19
0
        public Message SecureMessage()
        {
            secprop = Message.Properties.Security ?? new SecurityMessageProperty();

            SecurityToken encToken =
                secprop.InitiatorToken != null ? secprop.InitiatorToken.SecurityToken : security.EncryptionToken;
            // FIXME: it might be still incorrect.
            SecurityToken signToken =
                Parameters == CounterParameters ? null :
                security.SigningToken;
            MessageProtectionOrder protectionOrder =
                security.MessageProtectionOrder;
            SecurityTokenSerializer serializer =
                security.TokenSerializer;
            SecurityBindingElement element =
                security.Element;
            SecurityAlgorithmSuite suite = element.DefaultAlgorithmSuite;

            string      messageId         = "uuid-" + Guid.NewGuid();
            int         identForMessageId = 1;
            XmlDocument doc = new XmlDocument();

            doc.PreserveWhitespace = true;

            // FIXME: get correct ReplyTo value
            if (Direction == MessageDirection.Input)
            {
                msg.Headers.ReplyTo = new EndpointAddress(Constants.WsaAnonymousUri);
            }

            if (MessageTo != null)
            {
                msg.Headers.To = MessageTo.Uri;
            }

            // wss:Security
            WSSecurityMessageHeader header =
                new WSSecurityMessageHeader(serializer);

            msg.Headers.Add(header);
            // 1. [Timestamp]
            if (element.IncludeTimestamp)
            {
                WsuTimestamp timestamp = new WsuTimestamp();
                timestamp.Id      = messageId + "-" + identForMessageId++;
                timestamp.Created = DateTime.Now;
                // FIXME: on service side, use element.LocalServiceSettings.TimestampValidityDuration
                timestamp.Expires = timestamp.Created.Add(element.LocalClientSettings.TimestampValidityDuration);
                header.AddContent(timestamp);
            }

            XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);

            nsmgr.AddNamespace("s", msg.Version.Envelope.Namespace);
            nsmgr.AddNamespace("o", Constants.WssNamespace);
            nsmgr.AddNamespace("u", Constants.WsuNamespace);
            nsmgr.AddNamespace("o11", Constants.Wss11Namespace);

            /*WrappedKey*/ SecurityToken primaryToken = null;
            DerivedKeySecurityToken      dkeyToken    = null;
            SecurityToken actualToken = null;
            SecurityKeyIdentifierClause actualClause = null;
            Signature sig = null;

            List <DerivedKeySecurityToken> derivedKeys =
                new List <DerivedKeySecurityToken> ();

            SymmetricAlgorithm masterKey = new RijndaelManaged();

            masterKey.KeySize = suite.DefaultSymmetricKeyLength;
            masterKey.Mode    = CipherMode.CBC;
            masterKey.Padding = PaddingMode.ISO10126;
            SymmetricAlgorithm actualKey = masterKey;

            // 2. [Encryption Token]

            // SecurityTokenInclusionMode
            // - Initiator or Recipient
            // - done or notyet. FIXME: not implemented yet
            // It also affects on key reference output

            bool includeEncToken =             // /* FIXME: remove this hack */Parameters is SslSecurityTokenParameters ? false :
                                   ShouldIncludeToken(
                Security.RecipientParameters.InclusionMode, false);
            bool includeSigToken =             // /* FIXME: remove this hack */ Parameters is SslSecurityTokenParameters ? false :
                                   ShouldIncludeToken(
                Security.InitiatorParameters.InclusionMode, false);

            SecurityKeyIdentifierClause encClause = ShouldOutputEncryptedKey ?
                                                    CounterParameters.CallCreateKeyIdentifierClause(encToken, !ShouldOutputEncryptedKey ? SecurityTokenReferenceStyle.Internal : includeEncToken ? Parameters.ReferenceStyle : SecurityTokenReferenceStyle.External) : null;

            MessagePartSpecification sigSpec = SignaturePart;
            MessagePartSpecification encSpec = EncryptionPart;

            // encryption key (possibly also used for signing)
            // FIXME: get correct SymmetricAlgorithm according to the algorithm suite
            if (secprop.EncryptionKey != null)
            {
                actualKey.Key = secprop.EncryptionKey;
            }

// FIXME: remove thid hack
            if (!ShouldOutputEncryptedKey)
            {
                primaryToken = secprop.ProtectionToken.SecurityToken as WrappedKeySecurityToken;
            }
            else
            {
                primaryToken =
                    // FIXME: remove this hack?
                    encToken is SecurityContextSecurityToken ? encToken :
                    new WrappedKeySecurityToken(messageId + "-" + identForMessageId++,
                                                actualKey.Key,
                                                // security.DefaultKeyWrapAlgorithm,
                                                Parameters.InternalHasAsymmetricKey ?
                                                suite.DefaultAsymmetricKeyWrapAlgorithm :
                                                suite.DefaultSymmetricKeyWrapAlgorithm,
                                                encToken,
                                                encClause != null ? new SecurityKeyIdentifier(encClause) : null);
            }

            // If it reuses request's encryption key, do not output.
            if (ShouldOutputEncryptedKey)
            {
                header.AddContent(primaryToken);
            }

            actualToken = primaryToken;

            // FIXME: I doubt it is correct...
            WrappedKeySecurityToken requestEncKey = ShouldOutputEncryptedKey ? null : primaryToken as WrappedKeySecurityToken;

            actualClause = requestEncKey == null ? (SecurityKeyIdentifierClause)
                           new LocalIdKeyIdentifierClause(actualToken.Id, typeof(WrappedKeySecurityToken)) :
                           new InternalEncryptedKeyIdentifierClause(SHA1.Create().ComputeHash(requestEncKey.GetWrappedKey()));

            // generate derived key if needed
            if (CounterParameters.RequireDerivedKeys)
            {
                RijndaelManaged deriv = new RijndaelManaged();
                deriv.KeySize = suite.DefaultEncryptionKeyDerivationLength;
                deriv.Mode    = CipherMode.CBC;
                deriv.Padding = PaddingMode.ISO10126;
                deriv.GenerateKey();
                dkeyToken = new DerivedKeySecurityToken(
                    GenerateId(doc),
                    null,                     // algorithm
                    actualClause,
                    new InMemorySymmetricSecurityKey(actualKey.Key),
                    null,                     // name
                    null,                     // generation
                    null,                     // offset
                    deriv.Key.Length,
                    null,                     // label
                    deriv.Key);
                derivedKeys.Add(dkeyToken);
                actualToken   = dkeyToken;
                actualKey.Key = ((SymmetricSecurityKey)dkeyToken.SecurityKeys [0]).GetSymmetricKey();
                actualClause  = new LocalIdKeyIdentifierClause(dkeyToken.Id);
                header.AddContent(dkeyToken);
            }

            ReferenceList refList = new ReferenceList();

            // When encrypted with DerivedKeyToken, put references
            // immediately after the derived token (not inside the
            // primary token).
            // Similarly, when we do not output EncryptedKey,
            // output ReferenceList in the same way.
            if (CounterParameters.RequireDerivedKeys ||
                !ShouldOutputEncryptedKey)
            {
                header.AddContent(refList);
            }
            else
            {
                ((WrappedKeySecurityToken)primaryToken).ReferenceList = refList;
            }

            // [Signature Confirmation]
            if (security.RequireSignatureConfirmation && secprop.ConfirmedSignatures.Count > 0)
            {
                foreach (string value in secprop.ConfirmedSignatures)
                {
                    header.AddContent(new Wss11SignatureConfirmation(GenerateId(doc), value));
                }
            }

            SupportingTokenInfoCollection tokenInfos =
                Direction == MessageDirection.Input ?
                security.CollectSupportingTokens(GetAction()) :
                new SupportingTokenInfoCollection();                  // empty

            foreach (SupportingTokenInfo tinfo in tokenInfos)
            {
                header.AddContent(tinfo.Token);
            }

            // populate DOM to sign.
            XPathNavigator nav = doc.CreateNavigator();

            using (XmlWriter w = nav.AppendChild()) {
                msg.WriteMessage(w);
            }

            XmlElement body    = doc.SelectSingleNode("/s:Envelope/s:Body/*", nsmgr) as XmlElement;
            string     bodyId  = null;
            XmlElement secElem = null;
            Collection <WSSignedXml> endorsedSignatures =
                new Collection <WSSignedXml> ();
            bool signatureProtection = (protectionOrder == MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature);

            // Below are o:Security contents that are not signed...
            if (includeSigToken && signToken != null)
            {
                header.AddContent(signToken);
            }

            switch (protectionOrder)
            {
            case MessageProtectionOrder.EncryptBeforeSign:
                // FIXME: implement
                throw new NotImplementedException();

            case MessageProtectionOrder.SignBeforeEncrypt:
            case MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature:

                // sign
                // see clause 8 of WS-SecurityPolicy C.2.2
                WSSignedXml sxml = new WSSignedXml(doc);
                SecurityTokenReferenceKeyInfo sigKeyInfo;

                sig = sxml.Signature;
                sig.SignedInfo.CanonicalizationMethod =
                    suite.DefaultCanonicalizationAlgorithm;
                foreach (XmlElement elem in doc.SelectNodes("/s:Envelope/s:Header/o:Security/u:Timestamp", nsmgr))
                {
                    CreateReference(sig, elem, elem.GetAttribute("Id", Constants.WsuNamespace));
                }
                foreach (XmlElement elem in doc.SelectNodes("/s:Envelope/s:Header/o:Security/o11:SignatureConfirmation", nsmgr))
                {
                    CreateReference(sig, elem, elem.GetAttribute("Id", Constants.WsuNamespace));
                }
                foreach (SupportingTokenInfo tinfo in tokenInfos)
                {
                    if (tinfo.Mode != SecurityTokenAttachmentMode.Endorsing)
                    {
                        XmlElement el = sxml.GetIdElement(doc, tinfo.Token.Id);
                        CreateReference(sig, el, el.GetAttribute("Id", Constants.WsuNamespace));
                    }
                }
                XmlNodeList nodes = doc.SelectNodes("/s:Envelope/s:Header/*", nsmgr);
                for (int i = 0; i < msg.Headers.Count; i++)
                {
                    MessageHeaderInfo h = msg.Headers [i];
                    if (h.Name == "Security" && h.Namespace == Constants.WssNamespace)
                    {
                        secElem = nodes [i] as XmlElement;
                    }
                    else if (sigSpec.HeaderTypes.Count == 0 ||
                             sigSpec.HeaderTypes.Contains(new XmlQualifiedName(h.Name, h.Namespace)))
                    {
                        string id = GenerateId(doc);
                        h.Id = id;
                        CreateReference(sig, nodes [i] as XmlElement, id);
                    }
                }
                if (sigSpec.IsBodyIncluded)
                {
                    bodyId = GenerateId(doc);
                    CreateReference(sig, body.ParentNode as XmlElement, bodyId);
                }

                if (security.DefaultSignatureAlgorithm == SignedXml.XmlDsigHMACSHA1Url)
                {
                    // FIXME: use appropriate hash algorithm
                    sxml.ComputeSignature(new HMACSHA1(actualKey.Key));
                    sigKeyInfo = new SecurityTokenReferenceKeyInfo(actualClause, serializer, doc);
                }
                else
                {
                    SecurityKeyIdentifierClause signClause =
                        CounterParameters.CallCreateKeyIdentifierClause(signToken, includeSigToken ? CounterParameters.ReferenceStyle : SecurityTokenReferenceStyle.External);
                    AsymmetricSecurityKey signKey = (AsymmetricSecurityKey)signToken.ResolveKeyIdentifierClause(signClause);
                    sxml.SigningKey = signKey.GetAsymmetricAlgorithm(security.DefaultSignatureAlgorithm, true);
                    sxml.ComputeSignature();
                    sigKeyInfo = new SecurityTokenReferenceKeyInfo(signClause, serializer, doc);
                }

                sxml.KeyInfo = new KeyInfo();
                sxml.KeyInfo.AddClause(sigKeyInfo);

                if (!signatureProtection)
                {
                    header.AddContent(sig);
                }

                // endorse the signature with (signed)endorsing
                // supporting tokens.

                foreach (SupportingTokenInfo tinfo in tokenInfos)
                {
                    switch (tinfo.Mode)
                    {
                    case SecurityTokenAttachmentMode.Endorsing:
                    case SecurityTokenAttachmentMode.SignedEndorsing:
                        if (sxml.Signature.Id == null)
                        {
                            sig.Id = GenerateId(doc);
                            secElem.AppendChild(sxml.GetXml());
                        }
                        WSSignedXml ssxml = new WSSignedXml(doc);
                        ssxml.Signature.SignedInfo.CanonicalizationMethod = suite.DefaultCanonicalizationAlgorithm;
                        CreateReference(ssxml.Signature, doc, sig.Id);
                        SecurityToken sst = tinfo.Token;
                        SecurityKey   ssk = sst.SecurityKeys [0];                                     // FIXME: could be different?
                        SecurityKeyIdentifierClause tclause = new LocalIdKeyIdentifierClause(sst.Id); // FIXME: could be different?
                        if (ssk is SymmetricSecurityKey)
                        {
                            SymmetricSecurityKey signKey = (SymmetricSecurityKey)ssk;
                            ssxml.ComputeSignature(signKey.GetKeyedHashAlgorithm(suite.DefaultSymmetricSignatureAlgorithm));
                        }
                        else
                        {
                            AsymmetricSecurityKey signKey = (AsymmetricSecurityKey)ssk;
                            ssxml.SigningKey = signKey.GetAsymmetricAlgorithm(suite.DefaultAsymmetricSignatureAlgorithm, true);
                            ssxml.ComputeSignature();
                        }
                        ssxml.KeyInfo.AddClause(new SecurityTokenReferenceKeyInfo(tclause, serializer, doc));
                        if (!signatureProtection)
                        {
                            header.AddContent(ssxml.Signature);
                        }
                        endorsedSignatures.Add(ssxml);

                        break;
                    }
                }

                // encrypt

                WSEncryptedXml exml = new WSEncryptedXml(doc);

                EncryptedData edata = Encrypt(body, actualKey, actualToken.Id, refList, actualClause, exml, doc);
                EncryptedXml.ReplaceElement(body, edata, false);

                // encrypt signature
                if (signatureProtection)
                {
                    XmlElement sigxml = sig.GetXml();
                    edata = Encrypt(sigxml, actualKey, actualToken.Id, refList, actualClause, exml, doc);
                    header.AddContent(edata);

                    foreach (WSSignedXml ssxml in endorsedSignatures)
                    {
                        sigxml = ssxml.GetXml();
                        edata  = Encrypt(sigxml, actualKey, actualToken.Id, refList, actualClause, exml, doc);
                        header.AddContent(edata);
                    }

                    if (security.RequireSignatureConfirmation)
                    {
                        Collection <Wss11SignatureConfirmation> confs = header.FindAll <Wss11SignatureConfirmation> ();
                        int count = 0;
                        foreach (XmlElement elem in doc.SelectNodes("/s:Envelope/s:Header/o:Security/o11:SignatureConfirmation", nsmgr))
                        {
                            edata = Encrypt(elem, actualKey, confs [count].Id, refList, actualClause, exml, doc);
                            EncryptedXml.ReplaceElement(elem, edata, false);
                            header.Contents.Insert(header.Contents.IndexOf(confs [count]), edata);
                            header.Contents.Remove(confs [count++]);
                        }
                    }
                }

                // encrypt Encrypted supporting tokens
                foreach (SupportingTokenInfo tinfo in tokenInfos)
                {
                    if (tinfo.Mode == SecurityTokenAttachmentMode.SignedEncrypted)
                    {
                        XmlElement el = exml.GetIdElement(doc, tinfo.Token.Id);
                        tinfo.Encrypted = Encrypt(el, actualKey, actualToken.Id, refList, actualClause, exml, doc);
                        EncryptedXml.ReplaceElement(el, tinfo.Encrypted, false);
                        header.Contents.Insert(header.Contents.IndexOf(tinfo.Token), tinfo.Encrypted);
                        header.Contents.Remove(tinfo.Token);
                    }
                }
                break;
            }

            Message ret = new WSSecurityMessage(Message.CreateMessage(msg.Version, msg.Headers.Action, new XmlNodeReader(doc.SelectSingleNode("/s:Envelope/s:Body/*", nsmgr) as XmlElement)), bodyId);

            ret.Properties.Security = (SecurityMessageProperty)secprop.CreateCopy();
            ret.Properties.Security.EncryptionKey = masterKey.Key;

            // FIXME: can we support TransportToken here?
            if (element is AsymmetricSecurityBindingElement)
            {
                ret.Properties.Security.InitiatorToken = new SecurityTokenSpecification(encToken, null);                  // FIXME: second argument
                ret.Properties.Security.InitiatorToken = new SecurityTokenSpecification(signToken, null);                 // FIXME: second argument
            }
            else
            {
                ret.Properties.Security.ProtectionToken = new SecurityTokenSpecification(primaryToken, null);
            }

            ret.Headers.Clear();
            ret.Headers.CopyHeadersFrom(msg);

            // Header contents are:
            //	- Timestamp
            //	- SignatureConfirmation if required
            //	- EncryptionToken if included
            //	- derived key token for EncryptionToken
            //	- ReferenceList for encrypted items
            //	- signed supporting tokens
            //	- signed endorsing supporting tokens
            //	(i.e. Signed/SignedEncrypted/SignedEndorsing)
            //	- Signature Token if different from enc token.
            //	- derived key token for sig token if different
            //	- Signature for:
            //		- Timestamp
            //		- supporting tokens (regardless of
            //		  its inclusion)
            //		- message parts in SignedParts
            //		- SignatureToken if TokenProtection
            //		  (regardless of its inclusion)
            //	- Signatures for the main signature (above),
            //	  for every endorsing token and signed
            //	  endorsing token.
            //

//MessageBuffer zzz = ret.CreateBufferedCopy (100000);
//ret = zzz.CreateMessage ();
//Console.WriteLine (zzz.CreateMessage ());
            return(ret);
        }
        private async Task <bool> InvokeCryptographyEndpointAsync()
        {
            // Metadata requests must be made via GET.
            // See http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationRequest
            if (!string.Equals(Request.Method, "GET", StringComparison.OrdinalIgnoreCase))
            {
                Logger.LogError("The discovery request was rejected because an invalid " +
                                "HTTP method was used: {Method}.", Request.Method);

                return(await SendCryptographyResponseAsync(new OpenIdConnectResponse
                {
                    Error = OpenIdConnectConstants.Errors.InvalidRequest,
                    ErrorDescription = "Invalid HTTP method: make sure to use GET."
                }));
            }

            var request = new OpenIdConnectRequest(Request.Query);

            // Note: set the message type before invoking the ExtractCryptographyRequest event.
            request.SetProperty(OpenIdConnectConstants.Properties.MessageType,
                                OpenIdConnectConstants.MessageTypes.CryptographyRequest);

            // Store the discovery request in the OWIN context.
            Context.SetOpenIdConnectRequest(request);

            var @event = new ExtractCryptographyRequestContext(Context, Options, request);
            await Options.Provider.ExtractCryptographyRequest(@event);

            if (@event.HandledResponse)
            {
                Logger.LogDebug("The discovery request was handled in user code.");

                return(true);
            }

            else if (@event.Skipped)
            {
                Logger.LogDebug("The default discovery request handling was skipped from user code.");

                return(false);
            }

            else if (@event.IsRejected)
            {
                Logger.LogError("The discovery request was rejected with the following error: {Error} ; {Description}",
                                /* Error: */ @event.Error ?? OpenIdConnectConstants.Errors.InvalidRequest,
                                /* Description: */ @event.ErrorDescription);

                return(await SendCryptographyResponseAsync(new OpenIdConnectResponse
                {
                    Error = @event.Error ?? OpenIdConnectConstants.Errors.InvalidRequest,
                    ErrorDescription = @event.ErrorDescription,
                    ErrorUri = @event.ErrorUri
                }));
            }

            Logger.LogInformation("The discovery request was successfully extracted " +
                                  "from the HTTP request: {Request}", request);

            var context = new ValidateCryptographyRequestContext(Context, Options, request);
            await Options.Provider.ValidateCryptographyRequest(context);

            if (context.HandledResponse)
            {
                Logger.LogDebug("The discovery request was handled in user code.");

                return(true);
            }

            else if (context.Skipped)
            {
                Logger.LogDebug("The default discovery request handling was skipped from user code.");

                return(false);
            }

            else if (!context.IsValidated)
            {
                Logger.LogError("The discovery request was rejected with the following error: {Error} ; {Description}",
                                /* Error: */ context.Error ?? OpenIdConnectConstants.Errors.InvalidRequest,
                                /* Description: */ context.ErrorDescription);

                return(await SendCryptographyResponseAsync(new OpenIdConnectResponse
                {
                    Error = context.Error ?? OpenIdConnectConstants.Errors.InvalidRequest,
                    ErrorDescription = context.ErrorDescription,
                    ErrorUri = context.ErrorUri
                }));
            }

            var notification = new HandleCryptographyRequestContext(Context, Options, request);

            foreach (var credentials in Options.SigningCredentials)
            {
                // If the signing key is not an asymmetric key, ignore it.
                if (!(credentials.SigningKey is AsymmetricSecurityKey))
                {
                    continue;
                }

                if (!credentials.SigningKey.IsSupportedAlgorithm(SecurityAlgorithms.RsaSha256Signature))
                {
                    Logger.LogInformation("An unsupported signing key was ignored and excluded from the " +
                                          "key set: {Type}. Only RSA asymmetric security keys can be exposed " +
                                          "via the JWKS endpoint.", credentials.SigningKey.GetType().Name);

                    continue;
                }

                // Try to extract a key identifier from the credentials.
                LocalIdKeyIdentifierClause identifier = null;
                credentials.SigningKeyIdentifier?.TryFind(out identifier);

                // Resolve the underlying algorithm from the security key.
                var algorithm = ((AsymmetricSecurityKey)credentials.SigningKey)
                                .GetAsymmetricAlgorithm(
                    algorithm: SecurityAlgorithms.RsaSha256Signature,
                    privateKey: false) as RSA;

                // Skip the key if an algorithm instance cannot be extracted.
                if (algorithm == null)
                {
                    Logger.LogWarning("A signing key was ignored because it was unable " +
                                      "to provide the requested algorithm instance.");

                    continue;
                }

                // Export the RSA public key to create a new JSON Web Key
                // exposing the exponent and the modulus parameters.
                var parameters = algorithm.ExportParameters(includePrivateParameters: false);

                Debug.Assert(parameters.Exponent != null &&
                             parameters.Modulus != null,
                             "RSA.ExportParameters() shouldn't return null parameters.");

                var key = new JsonWebKey
                {
                    Use = JsonWebKeyUseNames.Sig,
                    Kty = JsonWebAlgorithmsKeyTypes.RSA,

                    // Resolve the JWA identifier from the algorithm specified in the credentials.
                    Alg = OpenIdConnectServerHelpers.GetJwtAlgorithm(credentials.SignatureAlgorithm),

                    // Use the key identifier specified
                    // in the signing credentials.
                    Kid = identifier?.LocalId,

                    // Note: both E and N must be base64url-encoded.
                    // See https://tools.ietf.org/html/rfc7518#section-6.2.1.2
                    E = Base64UrlEncoder.Encode(parameters.Exponent),
                    N = Base64UrlEncoder.Encode(parameters.Modulus)
                };

                X509Certificate2 certificate = null;

                // Determine whether the signing credentials are directly based on a X.509 certificate.
                var x509SigningCredentials = credentials as X509SigningCredentials;
                if (x509SigningCredentials != null)
                {
                    certificate = x509SigningCredentials.Certificate;
                }

                // Skip looking for a X509SecurityKey in SigningCredentials.SigningKey
                // if a certificate has been found in the SigningCredentials instance.
                if (certificate == null)
                {
                    // Determine whether the security key is an asymmetric key embedded in a X.509 certificate.
                    var x509SecurityKey = credentials.SigningKey as X509SecurityKey;
                    if (x509SecurityKey != null)
                    {
                        certificate = x509SecurityKey.Certificate;
                    }
                }

                // Skip looking for a X509AsymmetricSecurityKey in SigningCredentials.SigningKey
                // if a certificate has been found in SigningCredentials or SigningCredentials.SigningKey.
                if (certificate == null)
                {
                    // Determine whether the security key is an asymmetric key embedded in a X.509 certificate.
                    var x509AsymmetricSecurityKey = credentials.SigningKey as X509AsymmetricSecurityKey;
                    if (x509AsymmetricSecurityKey != null)
                    {
                        // The X.509 certificate is not directly accessible when using X509AsymmetricSecurityKey.
                        // Reflection is the only way to get the certificate used to create the security key.
                        var field = typeof(X509AsymmetricSecurityKey).GetField(
                            name: "certificate",
                            bindingAttr: BindingFlags.Instance | BindingFlags.NonPublic);
                        Debug.Assert(field != null);

                        certificate = (X509Certificate2)field.GetValue(x509AsymmetricSecurityKey);
                    }
                }

                // If the signing key is embedded in a X.509 certificate, set
                // the x5t and x5c parameters using the certificate details.
                if (certificate != null)
                {
                    // x5t must be base64url-encoded.
                    // See https://tools.ietf.org/html/rfc7517#section-4.8
                    key.X5t = Base64UrlEncoder.Encode(certificate.GetCertHash());

                    // Unlike E or N, the certificates contained in x5c
                    // must be base64-encoded and not base64url-encoded.
                    // See https://tools.ietf.org/html/rfc7517#section-4.7
                    key.X5c.Add(Convert.ToBase64String(certificate.RawData));
                }

                notification.Keys.Add(key);
            }

            await Options.Provider.HandleCryptographyRequest(notification);

            if (notification.HandledResponse)
            {
                Logger.LogDebug("The discovery request was handled in user code.");

                return(true);
            }

            else if (notification.Skipped)
            {
                Logger.LogDebug("The default discovery request handling was skipped from user code.");

                return(false);
            }

            else if (notification.IsRejected)
            {
                Logger.LogError("The discovery request was rejected with the following error: {Error} ; {Description}",
                                /* Error: */ notification.Error ?? OpenIdConnectConstants.Errors.InvalidRequest,
                                /* Description: */ notification.ErrorDescription);

                return(await SendCryptographyResponseAsync(new OpenIdConnectResponse
                {
                    Error = notification.Error ?? OpenIdConnectConstants.Errors.InvalidRequest,
                    ErrorDescription = notification.ErrorDescription,
                    ErrorUri = notification.ErrorUri
                }));
            }

            var keys = new JArray();

            foreach (var key in notification.Keys)
            {
                var item = new JObject();

                // Ensure a key type has been provided.
                // See https://tools.ietf.org/html/rfc7517#section-4.1
                if (string.IsNullOrEmpty(key.Kty))
                {
                    Logger.LogError("A JSON Web Key was excluded from the key set because " +
                                    "it didn't contain the mandatory 'kid' parameter.");

                    continue;
                }

                // Create a dictionary associating the
                // JsonWebKey components with their values.
                var parameters = new Dictionary <string, string>
                {
                    [JsonWebKeyParameterNames.Kid]    = key.Kid,
                    [JsonWebKeyParameterNames.Use]    = key.Use,
                    [JsonWebKeyParameterNames.Kty]    = key.Kty,
                    [JsonWebKeyParameterNames.KeyOps] = key.KeyOps,
                    [JsonWebKeyParameterNames.Alg]    = key.Alg,
                    [JsonWebKeyParameterNames.E]      = key.E,
                    [JsonWebKeyParameterNames.N]      = key.N,
                    [JsonWebKeyParameterNames.X5t]    = key.X5t,
                    [JsonWebKeyParameterNames.X5u]    = key.X5u
                };

                foreach (var parameter in parameters)
                {
                    if (!string.IsNullOrEmpty(parameter.Value))
                    {
                        item.Add(parameter.Key, parameter.Value);
                    }
                }

                if (key.X5c.Count != 0)
                {
                    item.Add(JsonWebKeyParameterNames.X5c, new JArray(key.X5c));
                }

                keys.Add(item);
            }

            return(await SendCryptographyResponseAsync(new OpenIdConnectResponse
            {
                [OpenIdConnectConstants.Parameters.Keys] = keys
            }));
        }
Esempio n. 21
0
        public Message SecureMessage()
        {
            secprop = Message.Properties.Security ?? new SecurityMessageProperty();

            SecurityToken encToken =
                secprop.InitiatorToken != null ? secprop.InitiatorToken.SecurityToken : security.EncryptionToken;
            // FIXME: it might be still incorrect.
            SecurityToken signToken =
                Parameters == CounterParameters ? null :
                security.SigningToken;
            MessageProtectionOrder protectionOrder =
                security.MessageProtectionOrder;
            SecurityBindingElement element =
                security.Element;
            SecurityAlgorithmSuite suite = element.DefaultAlgorithmSuite;

            string      messageId         = "uuid-" + Guid.NewGuid();
            int         identForMessageId = 1;
            XmlDocument doc = new XmlDocument();

            doc.PreserveWhitespace = true;
            var action = msg.Headers.Action;

            if (msg.Version.Addressing != AddressingVersion.None)
            {
                AddAddressingToHeader(msg.Headers);
            }

            // wss:Security
            WSSecurityMessageHeader header =
                new WSSecurityMessageHeader(security.TokenSerializer);

            msg.Headers.Add(header);
            // 1. [Timestamp]
            if (element.IncludeTimestamp)
            {
                AddTimestampToHeader(header, messageId + "-" + identForMessageId++);
            }

            XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);

            nsmgr.AddNamespace("s", msg.Version.Envelope.Namespace);
            nsmgr.AddNamespace("o", Constants.WssNamespace);
            nsmgr.AddNamespace("u", Constants.WsuNamespace);
            nsmgr.AddNamespace("o11", Constants.Wss11Namespace);

            /*WrappedKey*/ SecurityToken primaryToken = null;
            SecurityToken actualToken = null;
            SecurityKeyIdentifierClause actualClause = null;



            SymmetricAlgorithm masterKey = new RijndaelManaged();

            masterKey.KeySize = suite.DefaultSymmetricKeyLength;
            masterKey.Mode    = CipherMode.CBC;
            masterKey.Padding = PaddingMode.ISO10126;
            SymmetricAlgorithm actualKey = masterKey;

            // 2. [Encryption Token]

            // SecurityTokenInclusionMode
            // - Initiator or Recipient
            // - done or notyet. FIXME: not implemented yet
            // It also affects on key reference output

            bool includeEncToken =             // /* FIXME: remove this hack */Parameters is SslSecurityTokenParameters ? false :
                                   ShouldIncludeToken(
                Security.RecipientParameters.InclusionMode, false);
            bool includeSigToken =             // /* FIXME: remove this hack */ Parameters is SslSecurityTokenParameters ? false :
                                   ShouldIncludeToken(
                Security.InitiatorParameters.InclusionMode, false);

            SecurityKeyIdentifierClause encClause = ShouldOutputEncryptedKey ?
                                                    CounterParameters.CallCreateKeyIdentifierClause(encToken, !ShouldOutputEncryptedKey ? SecurityTokenReferenceStyle.Internal : includeEncToken ? Parameters.ReferenceStyle : SecurityTokenReferenceStyle.External) : null;

            MessagePartSpecification encSpec = EncryptionPart;

            // encryption key (possibly also used for signing)
            // FIXME: get correct SymmetricAlgorithm according to the algorithm suite
            if (secprop.EncryptionKey != null)
            {
                actualKey.Key = secprop.EncryptionKey;
            }

// FIXME: remove thid hack
            if (!ShouldOutputEncryptedKey)
            {
                primaryToken = secprop.ProtectionToken.SecurityToken as WrappedKeySecurityToken;
            }
            else
            {
                primaryToken =
                    // FIXME: remove this hack?
                    encToken is SecurityContextSecurityToken ? encToken :
                    new WrappedKeySecurityToken(messageId + "-" + identForMessageId++,
                                                actualKey.Key,
                                                // security.DefaultKeyWrapAlgorithm,
                                                Parameters.InternalHasAsymmetricKey ?
                                                suite.DefaultAsymmetricKeyWrapAlgorithm :
                                                suite.DefaultSymmetricKeyWrapAlgorithm,
                                                encToken,
                                                encClause != null ? new SecurityKeyIdentifier(encClause) : null);
            }

            // If it reuses request's encryption key, do not output.
            if (ShouldOutputEncryptedKey)
            {
                header.AddContent(primaryToken);
            }

            actualToken = primaryToken;

            // FIXME: I doubt it is correct...
            WrappedKeySecurityToken requestEncKey = ShouldOutputEncryptedKey ? null : primaryToken as WrappedKeySecurityToken;

            actualClause = requestEncKey == null ? (SecurityKeyIdentifierClause)
                           new LocalIdKeyIdentifierClause(actualToken.Id, typeof(WrappedKeySecurityToken)) :
                           new InternalEncryptedKeyIdentifierClause(SHA1.Create().ComputeHash(requestEncKey.GetWrappedKey()));

            // generate derived key if needed
            if (CounterParameters.RequireDerivedKeys)
            {
                var dkeyToken = CreateDerivedKey(GenerateId(doc), actualClause, actualKey);
                actualToken   = dkeyToken;
                actualKey.Key = ((SymmetricSecurityKey)dkeyToken.SecurityKeys [0]).GetSymmetricKey();
                actualClause  = new LocalIdKeyIdentifierClause(dkeyToken.Id);
                header.AddContent(dkeyToken);
            }

            ReferenceList refList = new ReferenceList();

            // When encrypted with DerivedKeyToken, put references
            // immediately after the derived token (not inside the
            // primary token).
            // Similarly, when we do not output EncryptedKey,
            // output ReferenceList in the same way.
            if (CounterParameters.RequireDerivedKeys ||
                !ShouldOutputEncryptedKey)
            {
                header.AddContent(refList);
            }
            else
            {
                ((WrappedKeySecurityToken)primaryToken).ReferenceList = refList;
            }

            // [Signature Confirmation]
            if (security.RequireSignatureConfirmation && secprop.ConfirmedSignatures.Count > 0)
            {
                foreach (string value in secprop.ConfirmedSignatures)
                {
                    header.AddContent(new Wss11SignatureConfirmation(GenerateId(doc), value));
                }
            }

            SupportingTokenInfoCollection tokenInfos =
                Direction == MessageDirection.Input ?
                security.CollectSupportingTokens(GetAction()) :
                new SupportingTokenInfoCollection();                  // empty

            foreach (SupportingTokenInfo tinfo in tokenInfos)
            {
                header.AddContent(tinfo.Token);
            }

            // populate DOM to sign.
            XPathNavigator nav = doc.CreateNavigator();

            using (XmlWriter w = nav.AppendChild()) {
                msg.WriteMessage(w);
            }

            XmlElement body   = doc.SelectSingleNode("/s:Envelope/s:Body/*", nsmgr) as XmlElement;
            string     bodyId = null;
            Collection <WSSignedXml> endorsedSignatures =
                new Collection <WSSignedXml> ();
            bool signatureProtection = (protectionOrder == MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature);

            // Below are o:Security contents that are not signed...
            if (includeSigToken && signToken != null)
            {
                header.AddContent(signToken);
            }

            switch (protectionOrder)
            {
            case MessageProtectionOrder.EncryptBeforeSign:
                // FIXME: implement
                throw new NotImplementedException();

            case MessageProtectionOrder.SignBeforeEncrypt:
            case MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature:


                var sig = CreateSignature(doc, body, nsmgr, tokenInfos,
                                          actualClause, actualKey, signToken, includeSigToken,
                                          signatureProtection, header, endorsedSignatures,
                                          ref bodyId);


                // encrypt

                WSEncryptedXml exml = new WSEncryptedXml(doc);

                EncryptedData edata = Encrypt(body, actualKey, actualToken.Id, refList, actualClause, exml, doc, EncryptedXml.XmlEncElementContentUrl);
                EncryptedXml.ReplaceElement(body, edata, false);

                // encrypt signature
                if (signatureProtection)
                {
                    XmlElement sigxml = sig.GetXml();
                    edata = Encrypt(sigxml, actualKey, actualToken.Id, refList, actualClause, exml, doc, EncryptedXml.XmlEncElementUrl);
                    header.AddContent(edata);

                    foreach (WSSignedXml ssxml in endorsedSignatures)
                    {
                        sigxml = ssxml.GetXml();
                        edata  = Encrypt(sigxml, actualKey, actualToken.Id, refList, actualClause, exml, doc, EncryptedXml.XmlEncElementUrl);
                        header.AddContent(edata);
                    }

                    if (security.RequireSignatureConfirmation)
                    {
                        Collection <Wss11SignatureConfirmation> confs = header.FindAll <Wss11SignatureConfirmation> ();
                        int count = 0;
                        foreach (XmlElement elem in doc.SelectNodes("/s:Envelope/s:Header/o:Security/o11:SignatureConfirmation", nsmgr))
                        {
                            edata = Encrypt(elem, actualKey, confs [count].Id, refList, actualClause, exml, doc, EncryptedXml.XmlEncElementUrl);
                            EncryptedXml.ReplaceElement(elem, edata, false);
                            header.Contents.Insert(header.Contents.IndexOf(confs [count]), edata);
                            header.Contents.Remove(confs [count++]);
                        }
                    }
                }


                // encrypt Encrypted supporting tokens
                foreach (SupportingTokenInfo tinfo in tokenInfos)
                {
                    if (tinfo.Mode == SecurityTokenAttachmentMode.SignedEncrypted)
                    {
                        XmlElement el = exml.GetIdElement(doc, tinfo.Token.Id);
                        tinfo.Encrypted = Encrypt(el, actualKey, actualToken.Id, refList, actualClause, exml, doc, EncryptedXml.XmlEncElementUrl);
                        EncryptedXml.ReplaceElement(el, tinfo.Encrypted, false);
                        header.Contents.Insert(header.Contents.IndexOf(tinfo.Token), tinfo.Encrypted);
                        header.Contents.Remove(tinfo.Token);
                    }
                }
                break;
            }



            Message ret = new WSSecurityMessage(Message.CreateMessage(msg.Version, action, new XmlNodeReader(doc.SelectSingleNode("/s:Envelope/s:Body/*", nsmgr) as XmlElement)), bodyId);

            ret.Properties.Security = (SecurityMessageProperty)secprop.CreateCopy();
            ret.Properties.Security.EncryptionKey = masterKey.Key;

            // FIXME: can we support TransportToken here?
            if (element is AsymmetricSecurityBindingElement)
            {
                ret.Properties.Security.InitiatorToken = new SecurityTokenSpecification(encToken, null);                  // FIXME: second argument
                ret.Properties.Security.InitiatorToken = new SecurityTokenSpecification(signToken, null);                 // FIXME: second argument
            }
            else
            {
                ret.Properties.Security.ProtectionToken = new SecurityTokenSpecification(primaryToken, null);
            }

            ret.Headers.Clear();
            ret.Headers.CopyHeadersFrom(msg);

            // Header contents are:
            //	- Timestamp
            //	- SignatureConfirmation if required
            //	- EncryptionToken if included
            //	- derived key token for EncryptionToken
            //	- ReferenceList for encrypted items
            //	- signed supporting tokens
            //	- signed endorsing supporting tokens
            //	(i.e. Signed/SignedEncrypted/SignedEndorsing)
            //	- Signature Token if different from enc token.
            //	- derived key token for sig token if different
            //	- Signature for:
            //		- Timestamp
            //		- supporting tokens (regardless of
            //		  its inclusion)
            //		- message parts in SignedParts
            //		- SignatureToken if TokenProtection
            //		  (regardless of its inclusion)
            //	- Signatures for the main signature (above),
            //	  for every endorsing token and signed
            //	  endorsing token.
            //

//MessageBuffer zzz = ret.CreateBufferedCopy (100000);
//ret = zzz.CreateMessage ();
//Console.WriteLine (zzz.CreateMessage ());
            return(ret);
        }
 private void SignWithSupportingTokens()
 {
     SecurityToken[] endorsingSupportingTokens = this.elementContainer.GetEndorsingSupportingTokens();
     if (endorsingSupportingTokens != null)
     {
         for (int i = 0; i < endorsingSupportingTokens.Length; i++)
         {
             SecurityToken token2;
             SecurityKeyIdentifierClause clause2;
             SecurityToken token = endorsingSupportingTokens[i];
             SecurityKeyIdentifierClause tokenToDeriveIdentifier = this.endorsingTokenParameters[i].CreateKeyIdentifierClause(token, this.GetTokenReferenceStyle(this.endorsingTokenParameters[i]));
             if (tokenToDeriveIdentifier == null)
             {
                 throw TraceUtility.ThrowHelperError(new MessageSecurityException(System.ServiceModel.SR.GetString("TokenManagerCannotCreateTokenReference")), base.Message);
             }
             if (this.endorsingTokenParameters[i].RequireDerivedKeys && !this.endorsingTokenParameters[i].HasAsymmetricKey)
             {
                 string keyDerivationAlgorithm  = System.ServiceModel.Security.SecurityUtils.GetKeyDerivationAlgorithm(base.StandardsManager.MessageSecurityVersion.SecureConversationVersion);
                 DerivedKeySecurityToken token3 = new DerivedKeySecurityToken(-1, 0, base.AlgorithmSuite.GetSignatureKeyDerivationLength(token, base.StandardsManager.MessageSecurityVersion.SecureConversationVersion), null, 0x10, token, tokenToDeriveIdentifier, keyDerivationAlgorithm, this.GenerateId());
                 token2  = token3;
                 clause2 = new LocalIdKeyIdentifierClause(token3.Id, token3.GetType());
                 this.elementContainer.AddEndorsingDerivedSupportingToken(token3);
             }
             else
             {
                 token2  = token;
                 clause2 = tokenToDeriveIdentifier;
             }
             this.SignWithSupportingToken(token2, clause2);
         }
     }
     SecurityToken[] signedEndorsingSupportingTokens = this.elementContainer.GetSignedEndorsingSupportingTokens();
     if (signedEndorsingSupportingTokens != null)
     {
         for (int j = 0; j < signedEndorsingSupportingTokens.Length; j++)
         {
             SecurityToken token5;
             SecurityKeyIdentifierClause clause4;
             SecurityToken token4 = signedEndorsingSupportingTokens[j];
             SecurityKeyIdentifierClause clause3 = this.signedEndorsingTokenParameters[j].CreateKeyIdentifierClause(token4, this.GetTokenReferenceStyle(this.signedEndorsingTokenParameters[j]));
             if (clause3 == null)
             {
                 throw TraceUtility.ThrowHelperError(new MessageSecurityException(System.ServiceModel.SR.GetString("TokenManagerCannotCreateTokenReference")), base.Message);
             }
             if (this.signedEndorsingTokenParameters[j].RequireDerivedKeys && !this.signedEndorsingTokenParameters[j].HasAsymmetricKey)
             {
                 string derivationAlgorithm     = System.ServiceModel.Security.SecurityUtils.GetKeyDerivationAlgorithm(base.StandardsManager.MessageSecurityVersion.SecureConversationVersion);
                 DerivedKeySecurityToken token6 = new DerivedKeySecurityToken(-1, 0, base.AlgorithmSuite.GetSignatureKeyDerivationLength(token4, base.StandardsManager.MessageSecurityVersion.SecureConversationVersion), null, 0x10, token4, clause3, derivationAlgorithm, this.GenerateId());
                 token5  = token6;
                 clause4 = new LocalIdKeyIdentifierClause(token6.Id, token6.GetType());
                 this.elementContainer.AddSignedEndorsingDerivedSupportingToken(token6);
             }
             else
             {
                 token5  = token4;
                 clause4 = clause3;
             }
             this.SignWithSupportingToken(token5, clause4);
         }
     }
 }
Esempio n. 23
0
        Signature CreateSignature(XmlDocument doc, XmlElement body,
                                  XmlNamespaceManager nsmgr,
                                  SupportingTokenInfoCollection tokenInfos,
                                  SecurityKeyIdentifierClause actualClause,
                                  SymmetricAlgorithm actualKey,
                                  SecurityToken signToken,
                                  bool includeSigToken,
                                  bool signatureProtection,
                                  WSSecurityMessageHeader header,
                                  Collection <WSSignedXml> endorsedSignatures,
                                  ref string bodyId)
        {
            // sign
            // see clause 8 of WS-SecurityPolicy C.2.2
            WSSignedXml sxml = new WSSignedXml(doc);
            SecurityTokenReferenceKeyInfo sigKeyInfo;
            XmlElement secElem    = null;
            var        sigSpec    = SignaturePart;
            var        serializer = security.TokenSerializer;
            var        suite      = security.Element.DefaultAlgorithmSuite;

            var sig = sxml.Signature;

            sig.SignedInfo.CanonicalizationMethod =
                suite.DefaultCanonicalizationAlgorithm;
            foreach (XmlElement elem in doc.SelectNodes("/s:Envelope/s:Header/o:Security/u:Timestamp", nsmgr))
            {
                CreateReference(sig, elem, elem.GetAttribute("Id", Constants.WsuNamespace));
            }
            foreach (XmlElement elem in doc.SelectNodes("/s:Envelope/s:Header/o:Security/o11:SignatureConfirmation", nsmgr))
            {
                CreateReference(sig, elem, elem.GetAttribute("Id", Constants.WsuNamespace));
            }
            foreach (SupportingTokenInfo tinfo in tokenInfos)
            {
                if (tinfo.Mode != SecurityTokenAttachmentMode.Endorsing)
                {
                    XmlElement el = sxml.GetIdElement(doc, tinfo.Token.Id);
                    CreateReference(sig, el, el.GetAttribute("Id", Constants.WsuNamespace));
                }
            }
            XmlNodeList nodes = doc.SelectNodes("/s:Envelope/s:Header/*", nsmgr);

            for (int i = 0; i < msg.Headers.Count; i++)
            {
                MessageHeaderInfo h = msg.Headers [i];
                if (h.Name == "Security" && h.Namespace == Constants.WssNamespace)
                {
                    secElem = nodes [i] as XmlElement;
                }
                else if ((sigSpec.HeaderTypes.Count == 0 ||
                          sigSpec.HeaderTypes.Contains(new XmlQualifiedName(h.Name, h.Namespace))) &&
                         (msg.Version.Addressing != AddressingVersion.None ||
                          !String.Equals(h.Name, "Action", StringComparison.Ordinal)))
                {
                    string id = GenerateId(doc);
                    h.Id = id;
                    CreateReference(sig, nodes [i] as XmlElement, id);
                }
            }
            if (sigSpec.IsBodyIncluded)
            {
                bodyId = GenerateId(doc);
                CreateReference(sig, body.ParentNode as XmlElement, bodyId);
            }


            if (security.DefaultSignatureAlgorithm == SignedXml.XmlDsigHMACSHA1Url)
            {
                // FIXME: use appropriate hash algorithm
                sxml.ComputeSignature(new HMACSHA1(actualKey.Key));
                sigKeyInfo = new SecurityTokenReferenceKeyInfo(actualClause, serializer, doc);
            }
            else
            {
                SecurityKeyIdentifierClause signClause =
                    CounterParameters.CallCreateKeyIdentifierClause(signToken, includeSigToken ? CounterParameters.ReferenceStyle : SecurityTokenReferenceStyle.External);
                AsymmetricSecurityKey signKey = (AsymmetricSecurityKey)signToken.ResolveKeyIdentifierClause(signClause);
                sxml.SigningKey = signKey.GetAsymmetricAlgorithm(security.DefaultSignatureAlgorithm, true);
                sxml.ComputeSignature();
                sigKeyInfo = new SecurityTokenReferenceKeyInfo(signClause, serializer, doc);
            }

            sxml.KeyInfo = new KeyInfo();
            sxml.KeyInfo.AddClause(sigKeyInfo);

            if (!signatureProtection)
            {
                header.AddContent(sig);
            }

            // endorse the signature with (signed)endorsing
            // supporting tokens.

            foreach (SupportingTokenInfo tinfo in tokenInfos)
            {
                switch (tinfo.Mode)
                {
                case SecurityTokenAttachmentMode.Endorsing:
                case SecurityTokenAttachmentMode.SignedEndorsing:
                    if (sxml.Signature.Id == null)
                    {
                        sig.Id = GenerateId(doc);
                        secElem.AppendChild(sxml.GetXml());
                    }
                    WSSignedXml ssxml = new WSSignedXml(doc);
                    ssxml.Signature.SignedInfo.CanonicalizationMethod = suite.DefaultCanonicalizationAlgorithm;
                    CreateReference(ssxml.Signature, doc, sig.Id);
                    SecurityToken sst = tinfo.Token;
                    SecurityKey   ssk = sst.SecurityKeys [0];                                     // FIXME: could be different?
                    SecurityKeyIdentifierClause tclause = new LocalIdKeyIdentifierClause(sst.Id); // FIXME: could be different?
                    if (ssk is SymmetricSecurityKey)
                    {
                        SymmetricSecurityKey signKey = (SymmetricSecurityKey)ssk;
                        ssxml.ComputeSignature(signKey.GetKeyedHashAlgorithm(suite.DefaultSymmetricSignatureAlgorithm));
                    }
                    else
                    {
                        AsymmetricSecurityKey signKey = (AsymmetricSecurityKey)ssk;
                        ssxml.SigningKey = signKey.GetAsymmetricAlgorithm(suite.DefaultAsymmetricSignatureAlgorithm, true);
                        ssxml.ComputeSignature();
                    }
                    ssxml.KeyInfo.AddClause(new SecurityTokenReferenceKeyInfo(tclause, serializer, doc));
                    if (!signatureProtection)
                    {
                        header.AddContent(ssxml.Signature);
                    }
                    endorsedSignatures.Add(ssxml);

                    break;
                }
            }
            return(sig);
        }
        private async Task <bool> InvokeCryptographyEndpointAsync()
        {
            // Metadata requests must be made via GET.
            // See http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationRequest
            if (!string.Equals(Request.Method, "GET", StringComparison.OrdinalIgnoreCase))
            {
                Options.Logger.LogError("The discovery request was rejected because an invalid " +
                                        "HTTP method was used: {Method}.", Request.Method);

                return(await SendCryptographyResponseAsync(null, new OpenIdConnectMessage {
                    Error = OpenIdConnectConstants.Errors.InvalidRequest,
                    ErrorDescription = "Invalid HTTP method: make sure to use GET."
                }));
            }

            var request = new OpenIdConnectMessage(Request.Query);

            var context = new ValidateCryptographyRequestContext(Context, Options);
            await Options.Provider.ValidateCryptographyRequest(context);

            // Stop processing the request if Validated was not called.
            if (!context.IsValidated)
            {
                Options.Logger.LogError("The discovery request was rejected with the following error: {Error} ; {Description}",
                                        /* Error: */ context.Error ?? OpenIdConnectConstants.Errors.InvalidRequest,
                                        /* Description: */ context.ErrorDescription);

                return(await SendCryptographyResponseAsync(request, new OpenIdConnectMessage {
                    Error = context.Error ?? OpenIdConnectConstants.Errors.InvalidRequest,
                    ErrorDescription = context.ErrorDescription,
                    ErrorUri = context.ErrorUri
                }));
            }

            var notification = new HandleCryptographyRequestContext(Context, Options, request);

            foreach (var credentials in Options.EncryptingCredentials)
            {
                // Ignore the key if it's not supported.
                if (!(credentials.SecurityKey is AsymmetricSecurityKey) ||
                    (!credentials.SecurityKey.IsSupportedAlgorithm(SecurityAlgorithms.RsaOaepKeyWrap) &&
                     !credentials.SecurityKey.IsSupportedAlgorithm(SecurityAlgorithms.RsaV15KeyWrap)))
                {
                    Options.Logger.LogInformation("An unsupported encryption key was ignored and excluded " +
                                                  "from the key set: {Type}. Only asymmetric security keys " +
                                                  "supporting RSA1_5 or RSA-OAEP can be exposed via the JWKS " +
                                                  "endpoint.", credentials.SecurityKey.GetType().Name);

                    continue;
                }

                // Try to extract a key identifier from the credentials.
                LocalIdKeyIdentifierClause identifier = null;
                credentials.SecurityKeyIdentifier?.TryFind(out identifier);

                // Resolve the underlying algorithm from the security key.
                var algorithm = (RSA)((AsymmetricSecurityKey)credentials.SecurityKey)
                                .GetAsymmetricAlgorithm(
                    algorithm: SecurityAlgorithms.RsaOaepKeyWrap,
                    privateKey: false);

                // Skip the key if a RSA instance cannot be retrieved.
                if (algorithm == null)
                {
                    Options.Logger.LogError("An encryption key was ignored because it was unable " +
                                            "to provide the requested RSA instance.");

                    continue;
                }

                // Export the RSA public key to create a new JSON Web Key
                // exposing the exponent and the modulus parameters.
                var parameters = algorithm.ExportParameters(includePrivateParameters: false);
                Debug.Assert(parameters.Exponent != null, "A null exponent was returned by RSA.ExportParameters()");
                Debug.Assert(parameters.Modulus != null, "A null modulus was returned by RSA.ExportParameters()");

                var key = new JsonWebKey {
                    Use = JsonWebKeyUseNames.Enc,
                    Kty = JsonWebAlgorithmsKeyTypes.RSA,

                    // Resolve the JWA identifier from the algorithm specified in the credentials.
                    Alg = OpenIdConnectServerHelpers.GetJwtAlgorithm(credentials.Algorithm),

                    // Use the key identifier specified
                    // in the signing credentials.
                    Kid = identifier.LocalId,

                    // Both E and N must be base64url-encoded.
                    // See http://tools.ietf.org/html/draft-ietf-jose-json-web-key-31#appendix-A.1
                    E = Base64UrlEncoder.Encode(parameters.Exponent),
                    N = Base64UrlEncoder.Encode(parameters.Modulus)
                };

                X509Certificate2 x509Certificate = null;

                // Determine whether the encrypting credentials are directly based on a X.509 certificate.
                var x509EncryptingCredentials = credentials as X509EncryptingCredentials;
                if (x509EncryptingCredentials != null)
                {
                    x509Certificate = x509EncryptingCredentials.Certificate;
                }

                // Skip looking for a X509SecurityKey in EncryptingCredentials.SecurityKey
                // if a certificate has been found in the EncryptingCredentials instance.
                if (x509Certificate == null)
                {
                    // Determine whether the security key is an asymmetric key embedded in a X.509 certificate.
                    var x509SecurityKey = credentials.SecurityKey as X509SecurityKey;
                    if (x509SecurityKey != null)
                    {
                        x509Certificate = x509SecurityKey.Certificate;
                    }
                }

                // Skip looking for a X509AsymmetricSecurityKey in EncryptingCredentials.SecurityKey
                // if a certificate has been found in EncryptingCredentials or EncryptingCredentials.SecurityKey.
                if (x509Certificate == null)
                {
                    // Determine whether the security key is an asymmetric key embedded in a X.509 certificate.
                    var x509AsymmetricSecurityKey = credentials.SecurityKey as X509AsymmetricSecurityKey;
                    if (x509AsymmetricSecurityKey != null)
                    {
                        // The X.509 certificate is not directly accessible when using X509AsymmetricSecurityKey.
                        // Reflection is the only way to get the certificate used to create the security key.
                        var field = typeof(X509AsymmetricSecurityKey).GetField(
                            name: "certificate",
                            bindingAttr: BindingFlags.Instance | BindingFlags.NonPublic);
                        Debug.Assert(field != null);

                        x509Certificate = (X509Certificate2)field.GetValue(x509AsymmetricSecurityKey);
                    }
                }

                // If the encryption key is embedded in a X.509 certificate, set
                // the x5t and x5c parameters using the certificate details.
                if (x509Certificate != null)
                {
                    // x5t must be base64url-encoded.
                    // See http://tools.ietf.org/html/draft-ietf-jose-json-web-key-31#section-4.8
                    key.X5t = Base64UrlEncoder.Encode(x509Certificate.GetCertHash());

                    // Unlike E or N, the certificates contained in x5c
                    // must be base64-encoded and not base64url-encoded.
                    // See http://tools.ietf.org/html/draft-ietf-jose-json-web-key-31#section-4.7
                    key.X5c.Add(Convert.ToBase64String(x509Certificate.RawData));
                }

                notification.Keys.Add(key);
            }

            foreach (var credentials in Options.SigningCredentials)
            {
                // Ignore the key if it's not supported.
                if (!(credentials.SigningKey is AsymmetricSecurityKey) ||
                    !credentials.SigningKey.IsSupportedAlgorithm(SecurityAlgorithms.RsaSha256Signature))
                {
                    Options.Logger.LogInformation("An unsupported signing key was ignored and excluded " +
                                                  "from the key set: {Type}. Only asymmetric security keys " +
                                                  "supporting RS256, RS384 or RS512 can be exposed " +
                                                  "via the JWKS endpoint.", credentials.SigningKey.GetType().Name);

                    continue;
                }

                // Try to extract a key identifier from the credentials.
                LocalIdKeyIdentifierClause identifier = null;
                credentials.SigningKeyIdentifier?.TryFind(out identifier);

                // Resolve the underlying algorithm from the security key.
                var algorithm = (RSA)((AsymmetricSecurityKey)credentials.SigningKey)
                                .GetAsymmetricAlgorithm(
                    algorithm: SecurityAlgorithms.RsaOaepKeyWrap,
                    privateKey: false);

                // Skip the key if a RSA instance cannot be retrieved.
                if (algorithm == null)
                {
                    Options.Logger.LogError("A signing key was ignored because it was unable " +
                                            "to provide the requested RSA instance.");

                    continue;
                }

                // Export the RSA public key to create a new JSON Web Key
                // exposing the exponent and the modulus parameters.
                var parameters = algorithm.ExportParameters(includePrivateParameters: false);
                Debug.Assert(parameters.Exponent != null, "A null exponent was returned by RSA.ExportParameters()");
                Debug.Assert(parameters.Modulus != null, "A null modulus was returned by RSA.ExportParameters()");

                var key = new JsonWebKey {
                    Use = JsonWebKeyUseNames.Sig,
                    Kty = JsonWebAlgorithmsKeyTypes.RSA,

                    // Resolve the JWA identifier from the algorithm specified in the credentials.
                    Alg = OpenIdConnectServerHelpers.GetJwtAlgorithm(credentials.SignatureAlgorithm),

                    // Use the key identifier specified
                    // in the signing credentials.
                    Kid = identifier?.LocalId,

                    // Both E and N must be base64url-encoded.
                    // See http://tools.ietf.org/html/draft-ietf-jose-json-web-key-31#appendix-A.1
                    E = Base64UrlEncoder.Encode(parameters.Exponent),
                    N = Base64UrlEncoder.Encode(parameters.Modulus)
                };

                X509Certificate2 x509Certificate = null;

                // Determine whether the signing credentials are directly based on a X.509 certificate.
                var x509SigningCredentials = credentials as X509SigningCredentials;
                if (x509SigningCredentials != null)
                {
                    x509Certificate = x509SigningCredentials.Certificate;
                }

                // Skip looking for a X509SecurityKey in SigningCredentials.SigningKey
                // if a certificate has been found in the SigningCredentials instance.
                if (x509Certificate == null)
                {
                    // Determine whether the security key is an asymmetric key embedded in a X.509 certificate.
                    var x509SecurityKey = credentials.SigningKey as X509SecurityKey;
                    if (x509SecurityKey != null)
                    {
                        x509Certificate = x509SecurityKey.Certificate;
                    }
                }

                // Skip looking for a X509AsymmetricSecurityKey in SigningCredentials.SigningKey
                // if a certificate has been found in SigningCredentials or SigningCredentials.SigningKey.
                if (x509Certificate == null)
                {
                    // Determine whether the security key is an asymmetric key embedded in a X.509 certificate.
                    var x509AsymmetricSecurityKey = credentials.SigningKey as X509AsymmetricSecurityKey;
                    if (x509AsymmetricSecurityKey != null)
                    {
                        // The X.509 certificate is not directly accessible when using X509AsymmetricSecurityKey.
                        // Reflection is the only way to get the certificate used to create the security key.
                        var field = typeof(X509AsymmetricSecurityKey).GetField(
                            name: "certificate",
                            bindingAttr: BindingFlags.Instance | BindingFlags.NonPublic);
                        Debug.Assert(field != null);

                        x509Certificate = (X509Certificate2)field.GetValue(x509AsymmetricSecurityKey);
                    }
                }

                // If the signing key is embedded in a X.509 certificate, set
                // the x5t and x5c parameters using the certificate details.
                if (x509Certificate != null)
                {
                    // x5t must be base64url-encoded.
                    // See http://tools.ietf.org/html/draft-ietf-jose-json-web-key-31#section-4.8
                    key.X5t = Base64UrlEncoder.Encode(x509Certificate.GetCertHash());

                    // Unlike E or N, the certificates contained in x5c
                    // must be base64-encoded and not base64url-encoded.
                    // See http://tools.ietf.org/html/draft-ietf-jose-json-web-key-31#section-4.7
                    key.X5c.Add(Convert.ToBase64String(x509Certificate.RawData));
                }

                notification.Keys.Add(key);
            }

            await Options.Provider.HandleCryptographyRequest(notification);

            if (notification.HandledResponse)
            {
                return(true);
            }

            else if (notification.Skipped)
            {
                return(false);
            }

            var response = new JObject();
            var keys     = new JArray();

            foreach (var key in notification.Keys)
            {
                var item = new JObject();

                // Ensure a key type has been provided.
                // See http://tools.ietf.org/html/draft-ietf-jose-json-web-key-31#section-4.1
                if (string.IsNullOrEmpty(key.Kty))
                {
                    Options.Logger.LogError("A JSON Web Key was excluded from the key set because " +
                                            "it didn't contain the mandatory 'kid' parameter.");

                    continue;
                }

                // Create a dictionary associating the
                // JsonWebKey components with their values.
                var parameters = new Dictionary <string, string> {
                    { JsonWebKeyParameterNames.Kid, key.Kid },
                    { JsonWebKeyParameterNames.Use, key.Use },
                    { JsonWebKeyParameterNames.Kty, key.Kty },
                    { JsonWebKeyParameterNames.KeyOps, key.KeyOps },
                    { JsonWebKeyParameterNames.Alg, key.Alg },
                    { JsonWebKeyParameterNames.E, key.E },
                    { JsonWebKeyParameterNames.N, key.N },
                    { JsonWebKeyParameterNames.X5t, key.X5t },
                    { JsonWebKeyParameterNames.X5u, key.X5u }
                };

                foreach (var parameter in parameters)
                {
                    if (!string.IsNullOrEmpty(parameter.Value))
                    {
                        item.Add(parameter.Key, parameter.Value);
                    }
                }

                if (key.X5c.Count != 0)
                {
                    item.Add(JsonWebKeyParameterNames.X5c, JArray.FromObject(key.X5c));
                }

                keys.Add(item);
            }

            response.Add(JsonWebKeyParameterNames.Keys, keys);

            return(await SendCryptographyResponseAsync(request, response));
        }