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())); }
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); }
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); } }
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()); } }
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)); } }
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 })); }
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); } } }
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)); }