예제 #1
0
        private JwtPayloadDocument(JwtDocument document, byte control, int issIdx)
        {
            _document = document;
            _control  = control;

            _iss = issIdx < 0 ? default : new JwtElement(_document, issIdx);
        }
예제 #2
0
 internal JwtDocument()
 {
     _isDisposable       = false;
     _utf8Json           = new byte[1];
     _disposableRegistry = new List <IDisposable>(0);
     _root = new JwtElement(this, 0);
 }
예제 #3
0
        internal bool TryGetNamedPropertyValue(ReadOnlySpan <char> propertyName, out JwtElement value)
        {
            JsonRow row;

            int maxBytes = Utf8.GetMaxByteCount(propertyName.Length);
            int endIndex = _parsedData.Length;

            if (maxBytes < JsonConstants.StackallocThreshold)
            {
                Span <byte> utf8Name = stackalloc byte[JsonConstants.StackallocThreshold];
                int         len      = JsonReaderHelper.GetUtf8FromText(propertyName, utf8Name);
                utf8Name = utf8Name.Slice(0, len);

                return(TryGetNamedPropertyValue(
                           endIndex,
                           utf8Name,
                           out value));
            }

            // Unescaping the property name will make the string shorter (or the same)
            // So the first viable candidate is one whose length in bytes matches, or
            // exceeds, our length in chars.
            //
            // The maximal escaping seems to be 6 -> 1 ("\u0030" => "0"), but just transcode
            // and switch once one viable long property is found.
            int minBytes = propertyName.Length;

            for (int candidateIndex = 0; candidateIndex <= endIndex; candidateIndex += JsonRow.Size * 2)
            {
                row = _parsedData.Get(candidateIndex);
                Debug.Assert(row.TokenType == JsonTokenType.PropertyName);

                if (row.Length >= minBytes)
                {
                    byte[] tmpUtf8 = ArrayPool <byte> .Shared.Rent(maxBytes);

                    Span <byte> utf8Name = default;

                    try
                    {
                        int len = JsonReaderHelper.GetUtf8FromText(propertyName, tmpUtf8);
                        utf8Name = tmpUtf8.AsSpan(0, len);

                        return(TryGetNamedPropertyValue(
                                   candidateIndex,
                                   utf8Name,
                                   out value));
                    }
                    finally
                    {
                        ArrayPool <byte> .Shared.Return(tmpUtf8);
                    }
                }
            }

            // None of the property names were within the range that the UTF-8 encoding would have been.
            value = default;
            return(false);
        }
예제 #4
0
        /// <summary>Gets the value associated with the specified key.</summary>
        public bool TryGetProperty(string key, out JwtElement value)
        {
            if (key == null)
            {
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
            }

            return(_root.TryGetProperty(key, out value));
        }
예제 #5
0
        internal bool TryGetNamedPropertyValue(ReadOnlySpan <byte> propertyName, out JwtElement value)
        {
            int endIndex = _parsedData.Length;

            return(TryGetNamedPropertyValue(
                       endIndex,
                       propertyName,
                       out value));
        }
        /// <summary>Parse the <see cref="JwtElement"/> into its <see cref="SignatureAlgorithm"/> representation.</summary>
        /// <param name="value"></param>
        /// <param name="algorithm"></param>
        public static bool TryParse(JwtElement value, [NotNullWhen(true)] out CompressionAlgorithm?algorithm)
        {
            if (value.ValueEquals(Def.Utf8Name))
            {
                algorithm = Def;
                return(true);
            }

            algorithm = null;
            return(false);
        }
예제 #7
0
        private JwtHeaderDocument(JwtDocument document, int algIdx, int encIdx, int kidIdx, int critIdx)
        {
            _document = document;

            _alg = algIdx < 0 ? default : new JwtElement(_document, algIdx);

                   _enc = encIdx < 0 ? default : new JwtElement(_document, encIdx);

                          _kid = kidIdx < 0 ? default : new JwtElement(_document, kidIdx);

                                 _crit = critIdx < 0 ? default : new JwtElement(_document, critIdx);
        }
예제 #8
0
        internal JwtDocument(ReadOnlyMemory <byte> utf8Json, JsonMetadata parsedData, byte[]?extraRentedBytes, bool isDisposable = true)
        {
            Debug.Assert(!utf8Json.IsEmpty);

            _utf8Json           = utf8Json;
            _parsedData         = parsedData;
            _extraRentedBytes   = extraRentedBytes;
            _root               = new JwtElement(this, 0);
            _isDisposable       = isDisposable;
            _disposableRegistry = new List <IDisposable>();

            // extraRentedBytes better be null if we're not disposable.
            Debug.Assert(isDisposable || extraRentedBytes == null);
        }
예제 #9
0
            private bool TryGetPolicy(JwtElement issuer, [NotNullWhen(true)] out SignatureValidationPolicy?policy)
            {
                for (int i = 0; i < _policies.Length; i++)
                {
                    var current = _policies[i];
                    if (issuer.ValueEquals(current.Key))
                    {
                        policy = current.Value;
                        return(true);
                    }
                }

                policy = null;
                return(false);
            }
예제 #10
0
        /// <summary>Parse the <see cref="JwtElement"/> into its <see cref="SignatureAlgorithm"/> representation.</summary>
        public static bool TryParse(JwtElement value, [NotNullWhen(true)] out CompressionAlgorithm?algorithm)
        {
            if (value.ValueEquals(Def.Utf8Name))
            {
                algorithm = Def;
                return(true);
            }

#if NET5_0_OR_GREATER
            Unsafe.SkipInit(out algorithm);
#else
            algorithm = default;
#endif
            return(false);
        }
예제 #11
0
        /// <summary>Parses the <see cref="JwtElement"/> into its <see cref="EncryptionAlgorithm"/> representation.</summary>
        public static bool TryParse(JwtElement value, [NotNullWhen(true)] out EncryptionAlgorithm?algorithm)
        {
            bool found;

            if (value.ValueEquals(A128CbcHS256._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = A128CbcHS256;
                found     = true;
            }
            else if (value.ValueEquals(A192CbcHS384._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = A192CbcHS384;
                found     = true;
            }
            else if (value.ValueEquals(A256CbcHS512._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = A256CbcHS512;
                found     = true;
            }
            else if (value.ValueEquals(A128Gcm._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = A128Gcm;
                found     = true;
            }
            else if (value.ValueEquals(A192Gcm._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = A192Gcm;
                found     = true;
            }
            else if (value.ValueEquals(A256Gcm._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = A256Gcm;
                found     = true;
            }
            else
            {
#if NET5_0_OR_GREATER
                Unsafe.SkipInit(out algorithm);
#else
                algorithm = default;
#endif
                found = false;
            }

            return(found);
        }
예제 #12
0
            private bool TryGetPolicy(JwtElement issuer, [NotNullWhen(true)] out SignatureValidationPolicy?policy)
            {
                for (int i = 0; i < _policies.Length; i++)
                {
                    var current = _policies[i];
                    if (issuer.ValueEquals(current.Key))
                    {
                        policy = current.Value;
                        return(true);
                    }
                }

#if NET5_0_OR_GREATER
                Unsafe.SkipInit(out policy);
#else
                policy = default;
#endif
                return(false);
            }
예제 #13
0
        /// <summary>Parses the <see cref="JwtElement"/> into its <see cref="EncryptionAlgorithm"/> representation.</summary>
        /// <param name="value"></param>
        /// <param name="algorithm"></param>
        public static bool TryParse(JwtElement value, [NotNullWhen(true)] out EncryptionAlgorithm?algorithm)
        {
            bool found;

            if (value.ValueEquals(A128CbcHS256._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = A128CbcHS256;
                found     = true;
            }
            else if (value.ValueEquals(A192CbcHS384._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = A192CbcHS384;
                found     = true;
            }
            else if (value.ValueEquals(A256CbcHS512._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = A256CbcHS512;
                found     = true;
            }
            else if (value.ValueEquals(A128Gcm._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = A128Gcm;
                found     = true;
            }
            else if (value.ValueEquals(A192Gcm._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = A192Gcm;
                found     = true;
            }
            else if (value.ValueEquals(A256Gcm._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = A256Gcm;
                found     = true;
            }
            else
            {
                algorithm = null;
                found     = false;
            }

            return(found);
        }
예제 #14
0
        public Jwk[] GetKeys(JwtElement kid)
        {
            if (kid.IsEmpty)
            {
                return(_keys.ToArray());
            }

            var keys = GetIdentifiedKeys();

            for (int i = 0; i < keys.Length; i++)
            {
                var key = keys[i];
                if (kid.ValueEquals(key.Key.EncodedUtf8Bytes))
                {
                    return(key.Value);
                }
            }

            return(Array.Empty <Jwk>());
        }
예제 #15
0
 internal JwtMemberElement(JwtElement value, string?name = null)
 {
     Value = value;
     _name = name;
 }
예제 #16
0
 internal bool TryGetProperty(ReadOnlySpan <byte> utf8PropertyName, out JwtElement value)
 => _parent.TryGetNamedPropertyValue(utf8PropertyName, out value);
예제 #17
0
        private bool TryGetNamedPropertyValue(
            int endIndex,
            ReadOnlySpan <byte> propertyName,
            out JwtElement value)
        {
            ReadOnlySpan <byte> documentSpan       = _utf8Json.Span;
            Span <byte>         utf8UnescapedStack = stackalloc byte[JsonConstants.StackallocThreshold];

            // Move to the row before the EndObject
            int index = 0;

            while (index < endIndex)
            {
                JsonRow row = _parsedData.Get(index);
                Debug.Assert(row.TokenType == JsonTokenType.PropertyName);

                ReadOnlySpan <byte> currentPropertyName = documentSpan.Slice(row.Location, row.Length);

                if (row.NeedUnescaping)
                {
                    // An escaped property name will be longer than an unescaped candidate, so only unescape
                    // when the lengths are compatible.
                    if (currentPropertyName.Length > propertyName.Length)
                    {
                        int idx = currentPropertyName.IndexOf(JsonConstants.BackSlash);
                        Debug.Assert(idx >= 0);

                        // If everything up to where the property name has a backslash matches, keep going.
                        if (propertyName.Length > idx &&
                            currentPropertyName.Slice(0, idx).SequenceEqual(propertyName.Slice(0, idx)))
                        {
                            int remaining = currentPropertyName.Length - idx;
                            int written   = 0;
                            byte[]? rented = null;

                            try
                            {
                                Span <byte> utf8Unescaped = remaining <= utf8UnescapedStack.Length ?
                                                            utf8UnescapedStack :
                                                            (rented = ArrayPool <byte> .Shared.Rent(remaining));

                                // Only unescape the part we haven't processed.
                                JsonReaderHelper.Unescape(currentPropertyName.Slice(idx), utf8Unescaped, 0, out written);

                                // If the unescaped remainder matches the input remainder, it's a match.
                                if (utf8Unescaped.Slice(0, written).SequenceEqual(propertyName.Slice(idx)))
                                {
                                    // If the property name is a match, the answer is the next element.
                                    value = new JwtElement(this, index + JsonRow.Size);
                                    return(true);
                                }
                            }
                            finally
                            {
                                if (rented != null)
                                {
                                    rented.AsSpan(0, written).Clear();
                                    ArrayPool <byte> .Shared.Return(rented);
                                }
                            }
                        }
                    }
                }
                else if (currentPropertyName.SequenceEqual(propertyName))
                {
                    // If the property name is a match, the answer is the next element.
                    value = new JwtElement(this, index + JsonRow.Size);
                    return(true);
                }

                // Move to the previous value
                index += JsonRow.Size * 2;
            }

            value = default;
            return(false);
        }
예제 #18
0
 /// <summary>
 ///   Looks for a claim named <paramref name="claimName"/> in the current JWT, returning
 ///   whether or not such a claim existed. When the claim exists <paramref name="value"/>
 ///   is assigned to the value of that claim.
 /// </summary>
 /// <param name="claimName">Name of the claim to find.</param>
 /// <param name="value">Receives the value of the located claim.</param>
 /// <returns>
 ///   <see langword="true"/> if the claim was found, <see langword="false"/> otherwise.
 /// </returns>
 /// <exception cref="InvalidOperationException">
 ///   This value is not <see cref="JsonValueKind.Object"/>.
 /// </exception>
 /// <exception cref="ObjectDisposedException">
 ///   The parent <see cref="JwtDocument"/> has been disposed.
 /// </exception>
 public bool TryGetClaim(string claimName, out JwtElement value)
 => _document.TryGetProperty(claimName, out value);
예제 #19
0
 /// <summary>
 ///   Looks for a header parameter named <paramref name="headerParameterName"/> in the current JWT, returning
 ///   whether or not such a parameter existed. When the parameter exists <paramref name="value"/>
 ///   is assigned to the value of that parameter.
 /// </summary>
 /// <param name="headerParameterName">Name of the parameter to find.</param>
 /// <param name="value">Receives the value of the located parameter.</param>
 /// <returns>
 ///   <see langword="true"/> if the parameter was found, <see langword="false"/> otherwise.
 /// </returns>
 /// <exception cref="InvalidOperationException">
 ///   This value is not <see cref="JsonValueKind.Object"/>.
 /// </exception>
 public bool TryGetHeaderParameter(ReadOnlySpan <byte> headerParameterName, out JwtElement value)
 => _document.TryGetProperty(headerParameterName, out value);
예제 #20
0
 /// <summary>
 ///   Looks for a header parameter named <paramref name="headerParameterName"/> in the current JWT, returning
 ///   whether or not such a parameter existed. When the parameter exists <paramref name="value"/>
 ///   is assigned to the value of that parameter.
 /// </summary>
 /// <param name="headerParameterName">Name of the parameter to find.</param>
 /// <param name="value">Receives the value of the located parameter.</param>
 /// <returns>
 ///   <see langword="true"/> if the parameter was found, <see langword="false"/> otherwise.
 /// </returns>
 /// <exception cref="InvalidOperationException">
 ///   This value is not <see cref="JsonValueKind.Object"/>.
 /// </exception>
 public bool TryGetHeaderParameter(JsonEncodedText headerParameterName, out JwtElement value)
 => _document.TryGetProperty(headerParameterName.EncodedUtf8Bytes, out value);
예제 #21
0
 internal bool TryGetProperty(ReadOnlySpan <char> propertyName, out JwtElement value)
 => _parent.TryGetNamedPropertyValue(propertyName, out value);
예제 #22
0
 /// <summary>
 ///   Looks for a claim named <paramref name="claimName"/> in the current JWT, returning
 ///   whether or not such a claim existed. When the claim exists <paramref name="value"/>
 ///   is assigned to the value of that claim.
 /// </summary>
 /// <param name="claimName">Name of the claim to find.</param>
 /// <param name="value">Receives the value of the located claim.</param>
 /// <returns>
 ///   <see langword="true"/> if the claim was found, <see langword="false"/> otherwise.
 /// </returns>
 /// <exception cref="InvalidOperationException">
 ///   This value is not <see cref="JsonValueKind.Object"/>.
 /// </exception>
 /// <exception cref="ObjectDisposedException">
 ///   The parent <see cref="JwtDocument"/> has been disposed.
 /// </exception>
 public bool TryGetClaim(ReadOnlySpan <byte> claimName, out JwtElement value)
 => _document.TryGetProperty(claimName, out value);
예제 #23
0
 /// <summary>
 ///   Looks for a claim named <paramref name="claimName"/> in the current JWT, returning
 ///   whether or not such a claim existed. When the claim exists <paramref name="value"/>
 ///   is assigned to the value of that claim.
 /// </summary>
 /// <param name="claimName">Name of the claim to find.</param>
 /// <param name="value">Receives the value of the located claim.</param>
 /// <returns>
 ///   <see langword="true"/> if the claim was found, <see langword="false"/> otherwise.
 /// </returns>
 /// <exception cref="InvalidOperationException">
 ///   This value is not <see cref="JsonValueKind.Object"/>.
 /// </exception>
 /// <exception cref="ObjectDisposedException">
 ///   The parent <see cref="JwtDocument"/> has been disposed.
 /// </exception>
 public bool TryGetClaim(JsonEncodedText claimName, out JwtElement value)
 => _document.TryGetProperty(claimName.EncodedUtf8Bytes, out value);
예제 #24
0
 /// <summary>Gets the value associated with the specified key.</summary>
 public bool TryGetProperty(ReadOnlySpan <byte> key, [NotNullWhen(true)] out JwtElement value)
 => _root.TryGetProperty(key, out value);
예제 #25
0
 /// <summary>
 ///   Looks for a header parameter named <paramref name="headerParameterName"/> in the current JWT, returning
 ///   whether or not such a parameter existed. When the parameter exists <paramref name="value"/>
 ///   is assigned to the value of that parameter.
 /// </summary>
 /// <param name="headerParameterName">Name of the header parameter to find.</param>
 /// <param name="value">Receives the value of the located parameter.</param>
 /// <returns>
 ///   <see langword="true"/> if the parameter was found, <see langword="false"/> otherwise.
 /// </returns>
 /// <exception cref="InvalidOperationException">
 ///   This value is not <see cref="JsonValueKind.Object"/>.
 /// </exception>
 public bool TryGetHeaderParameter(string headerParameterName, out JwtElement value)
 => _document.TryGetProperty(headerParameterName, out value);
        /// <summary>Parses the <see cref="JwtElement"/> into its <see cref="KeyManagementAlgorithm"/> representation.</summary>
        public static bool TryParse(JwtElement value, [NotNullWhen(true)] out KeyManagementAlgorithm?algorithm)
        {
            if (value.ValueEquals(Dir._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = Dir;
                goto Found;
            }
            else if (value.ValueEquals(A128KW._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = A128KW;
                goto Found;
            }
            else if (value.ValueEquals(A192KW._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = A192KW;
                goto Found;
            }
            else if (value.ValueEquals(A256KW._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = A256KW;
                goto Found;
            }
            else if (value.ValueEquals(Rsa1_5._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = Rsa1_5;
                goto Found;
            }
            else if (value.ValueEquals(EcdhEs._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = EcdhEs;
                goto Found;
            }
            else if (value.ValueEquals(RsaOaep._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = RsaOaep;
                goto Found;
            }
            else if (value.ValueEquals(A128GcmKW._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = A128GcmKW;
                goto Found;
            }
            else if (value.ValueEquals(A192GcmKW._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = A192GcmKW;
                goto Found;
            }
            else if (value.ValueEquals(A256GcmKW._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = A256GcmKW;
                goto Found;
            }
            else if (value.ValueEquals(RsaOaep256._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = RsaOaep256;
                goto Found;
            }
            else if (value.ValueEquals(RsaOaep384._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = RsaOaep384;
                goto Found;
            }
            else if (value.ValueEquals(RsaOaep512._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = RsaOaep512;
                goto Found;
            }
            else if (value.ValueEquals(EcdhEsA128KW._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = EcdhEsA128KW;
                goto Found;
            }
            else if (value.ValueEquals(EcdhEsA192KW._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = EcdhEsA192KW;
                goto Found;
            }
            else if (value.ValueEquals(EcdhEsA256KW._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = EcdhEsA256KW;
                goto Found;
            }
            else if (value.ValueEquals(Pbes2HS256A128KW._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = Pbes2HS256A128KW;
                goto Found;
            }
            else if (value.ValueEquals(Pbes2HS384A192KW._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = Pbes2HS384A192KW;
                goto Found;
            }
            else if (value.ValueEquals(Pbes2HS512A256KW._utf8Name.EncodedUtf8Bytes))
            {
                algorithm = Pbes2HS512A256KW;
                goto Found;
            }

            algorithm = null;
            return(false);

Found:
            return(true);
        }
예제 #27
0
 internal bool TryGetProperty(string propertyName, out JwtElement value)
 => TryGetProperty(propertyName.AsSpan(), out value);