Exemple #1
0
        /// <summary>Returns a new instance of <see cref="Jwks"/>.</summary>
        /// <param name="issuer">The issuer of the keys.</param>
        /// <param name="json">A string that contains JSON Web Key parameters in JSON format.</param>
        public static Jwks FromJson(string issuer, string json)
        {
            if (json is null)
            {
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.json);
            }

            byte[]? jsonToReturn = null;
            try
            {
                int         length   = Utf8.GetMaxByteCount(json.Length);
                Span <byte> jsonSpan = length <= Constants.MaxStackallocBytes
                            ? stackalloc byte[length]
                            : (jsonToReturn = ArrayPool <byte> .Shared.Rent(length));
                length = Utf8.GetBytes(json, jsonSpan);
                return(FromJson(issuer, jsonSpan.Slice(0, length)));
            }
            finally
            {
                if (jsonToReturn != null)
                {
                    ArrayPool <byte> .Shared.Return(jsonToReturn);
                }
            }
        }
Exemple #2
0
        /// <summary>Decodes a string of UTF-8 base64url-encoded text.</summary>
        /// <remarks>This method allocate an array of bytes. Use <see cref="Decode(ReadOnlySpan{byte}, Span{byte})"/> when possible.</remarks>
        public static byte[] Decode(string data)
        {
            if (data is null)
            {
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.data);
            }

            int length = Utf8.GetMaxByteCount(data.Length);

            byte[]? utf8ArrayToReturn = null;
            try
            {
                Span <byte> tmp = length > Constants.MaxStackallocBytes
                    ? (utf8ArrayToReturn = ArrayPool <byte> .Shared.Rent(length))
                    : stackalloc byte[Constants.MaxStackallocBytes];
                int written = Utf8.GetBytes(data, tmp);
                return(Decode(tmp.Slice(0, written)));
            }
            finally
            {
                if (utf8ArrayToReturn != null)
                {
                    ArrayPool <byte> .Shared.Return(utf8ArrayToReturn);
                }
            }
        }
Exemple #3
0
        /// <inheritsdoc />
        public override void Encode(EncodingContext context)
        {
            if (Payload != null)
            {
                int payloadLength = Utf8.GetMaxByteCount(Payload.Length);
                byte[]? payloadToReturnToPool = null;
                Span <byte> encodedPayload = payloadLength > Constants.MaxStackallocBytes
                                 ? (payloadToReturnToPool = ArrayPool <byte> .Shared.Rent(payloadLength))
                                 : stackalloc byte[payloadLength];

                try
                {
                    int bytesWritten = Utf8.GetBytes(Payload, encodedPayload);
                    EncryptToken(encodedPayload.Slice(0, bytesWritten), context);
                }
                finally
                {
                    if (payloadToReturnToPool != null)
                    {
                        ArrayPool <byte> .Shared.Return(payloadToReturnToPool);
                    }
                }
            }
            else
            {
                ThrowHelper.ThrowInvalidOperationException_UndefinedPayload();
            }
        }
Exemple #4
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);
        }
Exemple #5
0
        /// <summary>Parses and validates a JWT encoded as a JWS or JWE in compact serialized format.</summary>
        /// <param name="token">The JWT encoded as JWE or JWS</param>
        /// <param name="policy">The validation policy.</param>
        /// <param name="jwt">The resulting <see cref="Jwt"/>.</param>
        public static bool TryParse(string token, TokenValidationPolicy policy, out Jwt jwt)
        {
            if (token is null)
            {
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.token);
            }

            if (policy is null)
            {
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.policy);
            }

            if (token.Length == 0)
            {
                jwt = new Jwt(TokenValidationError.MalformedToken());
                return(false);
            }

            int length = Utf8.GetMaxByteCount(token.Length);

            if (length > policy.MaximumTokenSizeInBytes)
            {
                jwt = new Jwt(TokenValidationError.MalformedToken());
                return(false);
            }

            byte[]? utf8ArrayToReturnToPool = null;
            var utf8Token = length <= Constants.MaxStackallocBytes
                  ? stackalloc byte[length]
                  : (utf8ArrayToReturnToPool = ArrayPool <byte> .Shared.Rent(length));

            try
            {
                int bytesWritten = Utf8.GetBytes(token, utf8Token);
                return(TryParse(utf8Token.Slice(0, bytesWritten), policy, out jwt));
            }
            finally
            {
                if (utf8ArrayToReturnToPool != null)
                {
                    ArrayPool <byte> .Shared.Return(utf8ArrayToReturnToPool);
                }
            }
        }
Exemple #6
0
        /// <summary>Encodes a string of UTF-8 text.</summary>
        /// <returns>The base64-url encoded string.</returns>
        /// <remarks>This method allocate an array of bytes. Use <see cref="Encode(ReadOnlySpan{byte}, Span{byte})"/> when possible.</remarks>
        public static byte[] Encode(ReadOnlySpan <char> data)
        {
            byte[]? utf8ArrayToReturn = null;
            try
            {
                int length   = Utf8.GetMaxByteCount(data.Length);
                var utf8Data = length > Constants.MaxStackallocBytes
                    ? (utf8ArrayToReturn = ArrayPool <byte> .Shared.Rent(length))
                    : stackalloc byte[Constants.MaxStackallocBytes];

                int written = Utf8.GetBytes(data, utf8Data);
                return(Encode(utf8Data.Slice(0, written)));
            }
            finally
            {
                if (utf8ArrayToReturn != null)
                {
                    ArrayPool <byte> .Shared.Return(utf8ArrayToReturn);
                }
            }
        }
Exemple #7
0
        /// <inheritsdoc />
        public override void Encode(EncodingContext context, IBufferWriter <byte> output)
        {
            int payloadLength = Utf8.GetMaxByteCount(Payload.Length);

            byte[]? payloadToReturnToPool = null;
            Span <byte> encodedPayload = payloadLength > Constants.MaxStackallocBytes
                             ? (payloadToReturnToPool = ArrayPool <byte> .Shared.Rent(payloadLength))
                             : stackalloc byte[payloadLength];

            try
            {
                int bytesWritten = Utf8.GetBytes(Payload, encodedPayload);
                EncryptToken(context, encodedPayload.Slice(0, bytesWritten), output);
            }
            finally
            {
                if (payloadToReturnToPool != null)
                {
                    ArrayPool <byte> .Shared.Return(payloadToReturnToPool);
                }
            }
        }