Esempio n. 1
0
        public static string VerifyCookie(string input, out long signTime, IPAddress remoteIp = null, uint validTime = uint.MaxValue)
        {
            if (hmacKey == null)
            {
                throw new InvalidOperationException();
            }

            signTime = long.MinValue;
            if (input == null)
            {
                return(null);
            }
            if (input.Length < 80)  //Minimum length (60 byte sig+metadata)
            {
                return(null);
            }
            if ((input.Length & 3) != 0)  //Length of a base64 string must be of multiples of 4
            {
                return(null);
            }

            try {
                var data = Convert.FromBase64String(input.Replace('.', '+').Replace('_', '/').Replace('-', '=')); //throws FormatException

                var computed = hmac.Value.ComputeHash(data, SigLength, data.Length - SigLength);                  //Compute signature
                int trash    = 0;
                for (int i = 0; i < SigLength; i++)                                                               //Compare the sig. (Avoiding timing attack)
                {
                    trash |= data[i] ^ computed[i];
                }
                if (trash != 0)      //sig mismatch, reject.
                {
                    return(null);
                }

                signTime = data.GetInt64(TsOffset);
                var currentTs = UnixTimestamp.CurrentMillisecondTimestamp;
                if (signTime > currentTs)      //Reject anything with a timestamp from the future
                {
                    return(null);
                }

                //Compute the validity period for this verification.
                //Subtract 1 to treat value 0 (defined as infinite) as greatest.
                validTime = Math.Min(data.GetUInt32(ValidityOffset) - 1, validTime - 1);
                if (validTime != uint.MaxValue)
                {
                    if ((signTime + validTime) < currentTs)  //Should be <=, but we've subtracted 1 from the original value.
                    {
                        return(null);
                    }
                }

                //all zeroes denotes don't care.
                if (!data.TrueForRange(IpAddrOffset, IpAddrLength, x => x == 0))
                {
                    if (remoteIp == null)  //No remote ip provided while a verification is required, reject.
                    {
                        return(null);
                    }
                    if (remoteIp.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                    {
                        remoteIp = remoteIp.MapToIPv6();
                    }
                    var ip = remoteIp.GetAddressBytes();
                    if (!ArrayEx.RangeEquals(data, IpAddrOffset, ip, 0, IpAddrLength))
                    {
                        return(null);
                    }
                }

                return(cookieEncoding.GetString(data, DataOffset, data.Length - DataOffset)); //throws ArgumentException
            } catch (FormatException) {
                return(null);
            } catch (ArgumentException) {
                return(null);
            }
        }