Exemplo n.º 1
0
        /// <summary>
        /// Process the SASL challenge message.
        /// </summary>
        /// <param name="challenge">The server challenge.</param>
        /// <returns>
        /// The challenge response.
        /// </returns>
        /// <remarks>
        /// SaltedPassword  := Hi(Normalize(password), salt, i)
        /// ClientKey       := HMAC(SaltedPassword, "Client Key")
        /// StoredKey       := H(ClientKey)
        /// AuthMessage     := client-first-message-bare + "," +
        ///                    server-first-message + "," +
        ///                    client-final-message-without-proof
        /// ClientSignature := HMAC(StoredKey, AuthMessage)
        /// ClientProof     := ClientKey XOR ClientSignature
        /// ServerKey       := HMAC(SaltedPassword, "Server Key")
        /// ServerSignature := HMAC(ServerKey, AuthMessage)
        /// </remarks>
        public SaslResponse ProcessChallenge(SaslChallenge challenge)
        {
            var password           = Normalize(this.connectionString.UserPassword);
            var decoded            = Convert.FromBase64String(challenge.Value);
            var serverFirstMessage = XmppEncoding.Utf8.GetString(decoded, 0, decoded.Length);
            var tokens             = SaslTokenizer.ToDictionary(serverFirstMessage);
            var snonce             = tokens["r"];
            var ssalt                = Convert.FromBase64String(tokens["s"]);
            var ssaltSize            = Convert.ToUInt32(tokens["i"]);
            var clientFinalMessageWP = $"c={XmppEncoding.Utf8.GetBytes("n,,").ToBase64String()},r={snonce}";
            var saltedPassword       = password.Rfc2898DeriveBytes(ssalt, ssaltSize, 20);
            var clientKey            = saltedPassword.ComputeHmacSha1("Client Key");
            var storedKey            = clientKey.ComputeSHA1Hash();
            var authMessage          = $"{this.clientFirstMessageBare},{serverFirstMessage},{clientFinalMessageWP}";
            var clientSignature      = storedKey.ComputeHmacSha1(authMessage);
            var clientProof          = clientKey.Xor(clientSignature);
            var clientFinalMessage   = $"{clientFinalMessageWP},p={clientProof.ToBase64String()}";
            var serverKey            = saltedPassword.ComputeHmacSha1("Server Key");

            this.serverSignature = serverKey.ComputeHmacSha1(authMessage).ToBase64String();

            return(new SaslResponse {
                Value = clientFinalMessage.ToBase64String()
            });
        }
Exemplo n.º 2
0
        private static SaslChallengeAction GetChallengeAction(SaslChallenge saslChallenge)
        {
            var challengeBytes = saslChallenge.Challenge.Array;

            if (challengeBytes == null || challengeBytes.Length == 0)
            {
                throw new AmqpException(AmqpErrorCode.InvalidField, "Sasl challenge message is missing or empty.");
            }

            if (challengeBytes[0] == 0x0)
            {
                return(SaslChallengeAction.First);
            }

            if ((challengeBytes[0] & SaslControlByteMask.InterimSegment) != 0x0)
            {
                if ((challengeBytes[0] & SaslControlByteMask.FinalSegment) != 0x0)
                {
                    return(SaslChallengeAction.Final);
                }

                return(SaslChallengeAction.Interim);
            }

            throw new AmqpException(AmqpErrorCode.InvalidField,
                                    $"Sasl challenge control byte contains invalid data: {challengeBytes[0]:X}.");
        }
Exemplo n.º 3
0
        public void OnCommand_ReturnsAmqpException_WhenCommandNotSupported()
        {
            var command = new SaslChallenge();
            var profile = new AzureSaslProfileProxy();

            AmqpException exception = Should.Throw <AmqpException>(() => profile.CallOnCommand(command));

            exception.Error.Condition.ShouldBe((Symbol)ErrorCode.NotAllowed);
            exception.Message.ShouldBe(command.ToString());
        }
Exemplo n.º 4
0
        /// <summary>
        /// Process the SASL challenge message.
        /// </summary>
        /// <param name="challenge">The server challenge.</param>
        /// <returns>
        /// The challenge response.
        /// </returns>
        public SaslResponse ProcessChallenge(SaslChallenge challenge)
        {
            // Response to teh Authentication Information Request
            this.digestChallenge = DecodeDigestChallenge(challenge);

            if (this.digestChallenge.ContainsKey("rspauth"))
            {
                return(new SaslResponse());
            }

            return(null);
        }
        private void SaveEncodedNonceSegment(SaslChallenge saslChallenge)
        {
            var sequenceNumber = GetSequenceNumber(saslChallenge);

            if (_nextSequenceNumber != sequenceNumber)
            {
                throw new AmqpException(AmqpErrorCode.InvalidField,
                                        $"Invalid sequence number, expected: {_nextSequenceNumber}, actual: {sequenceNumber}.");
            }

            var nonceSegment = Encoding.UTF8.GetString(saslChallenge.Challenge.Array, 1,
                                                       saslChallenge.Challenge.Array.Length - 1);

            _encodedNonceStringBuilder.Append(nonceSegment);
            _nextSequenceNumber++;
        }
Exemplo n.º 6
0
        public override void OnChallenge(SaslChallenge challenge)
        {
            var challengeAction = GetChallengeAction(challenge);

            switch (challengeAction)
            {
            case SaslChallengeAction.First:
                SendStorageRootKey();
                break;

            case SaslChallengeAction.Interim:
                SaveEncodedNonceSegment(challenge);
                SendInterimResponse();
                break;

            case SaslChallengeAction.Final:
                SaveEncodedNonceSegment(challenge);
                SendLastResponse();
                break;
            }
        }
Exemplo n.º 7
0
        private void SaveEncodedNonceSegment(SaslChallenge saslChallenge)
        {
            var sequenceNumber = GetSequenceNumber(saslChallenge);

            if (_nextSequenceNumber != sequenceNumber)
            {
                throw new AmqpException(AmqpErrorCode.InvalidField,
                                        $"Invalid sequence number, expected: {_nextSequenceNumber}, actual: {sequenceNumber}.");
            }

            byte[] tempNonce = new byte[_nonceBuffer.Length];
            Buffer.BlockCopy(_nonceBuffer, 0, tempNonce, 0, _nonceBuffer.Length);

            _nonceBuffer = new byte[_nonceBuffer.Length + saslChallenge.Challenge.Array.Length - 1];
            Buffer.BlockCopy(tempNonce, 0, _nonceBuffer, 0, tempNonce.Length);
            Buffer.BlockCopy(
                saslChallenge.Challenge.Array,
                1,
                _nonceBuffer,
                tempNonce.Length,
                saslChallenge.Challenge.Array.Length - 1);
            _nextSequenceNumber++;
        }
Exemplo n.º 8
0
        private static Dictionary <string, string> DecodeDigestChallenge(SaslChallenge challenge)
        {
            var table    = new Dictionary <string, string>();
            var buffer   = Convert.FromBase64String(challenge.Value);
            var decoded  = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
            var keyPairs = Regex.Matches(decoded, @"([\w\s\d]*)\s*=\s*([^,]*)");

            foreach (Match match in keyPairs)
            {
                if (match.Success && match.Groups.Count == 3)
                {
                    string key   = match.Groups[1].Value.Trim();
                    string value = match.Groups[2].Value.Trim();

                    // Strip quotes from the value
                    if (value.StartsWith("\"", StringComparison.OrdinalIgnoreCase) ||
                        value.StartsWith("'", StringComparison.OrdinalIgnoreCase))
                    {
                        value = value.Remove(0, 1);
                    }
                    if (value.EndsWith("\"", StringComparison.OrdinalIgnoreCase) ||
                        value.EndsWith("'", StringComparison.OrdinalIgnoreCase))
                    {
                        value = value.Remove(value.Length - 1, 1);
                    }

                    if (key == "nonce" && table.ContainsKey(key))
                    {
                        return(null);
                    }

                    table.Add(key, value);
                }
            }

            return(table);
        }
Exemplo n.º 9
0
 private static byte GetSequenceNumber(SaslChallenge saslChallenge)
 {
     return((byte)(saslChallenge.Challenge.Array[0] & SaslControlByteMask.SequenceNumber));
 }
Exemplo n.º 10
0
 /// <summary>
 /// Process the SASL challenge message.
 /// </summary>
 /// <param name="challenge">The server challenge.</param>
 /// <returns>
 /// The challenge response.
 /// </returns>
 public SaslResponse ProcessChallenge(SaslChallenge challenge)
 {
     return(null);
 }
Exemplo n.º 11
0
        private Element CreateNode(XmlNodeResult nd, Element parent)
        {
            string ens;

            if (nd.Prefix != null)
            {
                RemObjects.InternetPack.XMPP.Elements.Attribute at = nd.Attribute.FirstOrDefault(a => a.Prefix == "xmlns" && a.Name == nd.Prefix);
                if (at == null)
                {
                    Element el = parent;
                    ens = string.Empty;
                    while (el != null)
                    {
                        RemObjects.InternetPack.XMPP.Elements.Attribute els = el.Attributes.Where(a => a.Prefix == "xmlns" && a.Name == nd.Prefix).FirstOrDefault();
                        if (els != null)
                        {
                            ens = els.Value;
                            break;
                        }
                        el = el.Parent;
                    }
                }
                else
                {
                    ens = at.Value;
                }
            }
            else
            {
                RemObjects.InternetPack.XMPP.Elements.Attribute at = nd.Attribute.FirstOrDefault(a => a.Prefix == null && a.Name == "xmlns");
                if (at == null)
                {
                    ens = string.Empty;
                }
                else
                {
                    ens = at.Value;
                }
            }
            Element res = null;

            switch (ens)
            {
            case Namespaces.ClientStreamNamespace:
            case Namespaces.ServerStreamNamespace:
            case "":
                if (ens == null && parent != null && parent.Type == ElementType.IQ && nd.Name == "error")
                {
                    res = new IQError();
                }
                else
                {
                    switch (nd.Name)
                    {
                    case "iq":
                        res = new IQ();
                        break;

                    case "presence":
                        res = new Presence();
                        break;

                    case "message":
                        res = new Message();
                        break;
                    }
                }
                break;

            case Namespaces.StreamNamespace:
                switch (nd.Name)
                {
                case "stream":

                    RemObjects.InternetPack.XMPP.Elements.Attribute att = nd.Attribute.FirstOrDefault(a => a.Prefix == null && a.Name == "xmlns");
                    if (att == null || att.Value == Namespaces.ClientStreamNamespace)
                    {
                        res = new ClientStream();
                    }
                    else
                    {
                        res = new ServerStream();
                    }
                    break;

                case "features":
                    res = new StreamFeatures();
                    break;

                case "error":
                    res = new StreamError();
                    break;
                }
                break;

            case Namespaces.StartTLSNamespace:
                switch (nd.Name)
                {
                case "starttls":
                    res = new StartTLS();
                    break;

                case "failure":
                    res = new StartTLSFailure();
                    break;

                case "proceed":
                    res = new StartTLSProceed();
                    break;
                }

                break;

            case Namespaces.SaslNamespace:
                switch (nd.Name)
                {
                case "mechanisms":
                    res = new Mechanisms();
                    break;

                case "auth":
                    res = new SaslAuth();
                    break;

                case "challenge":
                    res = new SaslChallenge();
                    break;

                case "response":
                    res = new SaslResponse();
                    break;

                case "abort":
                    res = new SaslAbort();
                    break;

                case "success":
                    res = new SaslSuccess();
                    break;

                case "failure":
                    res = new SaslFailure();
                    break;
                }
                break;
            }
            if (res == null)
            {
                res = new UnknownElement();
            }
            else
            {
                res.Attributes.Clear(); // default ones shouldn't be here during the reading process
            }
            if (parent != null)
            {
                res.Parent = parent;
                if (parent != fServerRoot)
                {
                    parent.Elements.Add(res);
                }
            }
            res.Prefix = nd.Prefix;
            res.Name   = nd.Name;
            foreach (var el in nd.Attribute)
            {
                res.Attributes.Add(el);
            }
            return(res);
        }