예제 #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, ReadOnlySpan <byte> json)
        {
            // a JWKS is :
            // {
            //   "keys": [
            //   { jwk1 },
            //   { jwk2 },
            //   ...
            //   ]
            // }
            var jwks   = new Jwks(issuer);
            var reader = new Utf8JsonReader(json, true, default);

            if (reader.Read() && reader.TokenType is JsonTokenType.StartObject && reader.Read())
            {
                while (reader.TokenType is JsonTokenType.PropertyName)
                {
                    var propertyName = reader.ValueSpan;
                    if (propertyName.Length == 4)
                    {
                        ref byte propertyNameRef = ref MemoryMarshal.GetReference(propertyName);
                        if (IntegerMarshal.ReadUInt32(ref propertyNameRef) == keys /* keys */)
                        {
                            if (reader.Read() && reader.TokenType is JsonTokenType.StartArray)
                            {
                                while (reader.Read() && reader.TokenType is JsonTokenType.StartObject)
                                {
                                    Jwk jwk = Jwk.FromJsonReader(ref reader);
                                    jwks.Add(jwk);
                                }

                                if (!(reader.TokenType is JsonTokenType.EndArray) || !reader.Read())
                                {
                                    ThrowHelper.ThrowInvalidOperationException_MalformedJwks();
                                }
                            }

                            continue;
                        }
                    }

                    reader.Read();
                    if (reader.TokenType >= JsonTokenType.String && reader.TokenType <= JsonTokenType.Null)
                    {
                        reader.Read();
                    }
                    else if (reader.TokenType == JsonTokenType.StartObject)
                    {
                        JsonParser.ConsumeJsonObject(ref reader);
                    }
                    else if (reader.TokenType == JsonTokenType.StartArray)
                    {
                        JsonParser.ConsumeJsonArray(ref reader);
                    }
                    else
                    {
                        ThrowHelper.ThrowInvalidOperationException_MalformedJwks();
                    }
                }
            }
예제 #2
0
파일: Jwks.cs 프로젝트: MortalFlesh/Jwt
        /// <summary>
        /// Returns a new instance of <see cref="Jwks"/>.
        /// </summary>
        /// <param name="json">a string that contains JSON Web Key parameters in JSON format.</param>
        /// <returns><see cref="Jwks"/></returns>
        public static Jwks FromJson(ReadOnlySpan <byte> json)
        {
            // a JWKS is :
            // {
            //   "keys": [
            //   { jwk1 },
            //   { jwk2 },
            //   ...
            //   ]
            // }
            var jwks   = new Jwks();
            var reader = new Utf8JsonReader(json, true, default);

            if (reader.Read() &&
                reader.TokenType is JsonTokenType.StartObject &&
                reader.Read() &&
                reader.TokenType is JsonTokenType.PropertyName)
            {
                var propertyName = reader.ValueSpan /* reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan */;
                if (propertyName.Length == 4)
                {
                    ref byte propertyNameRef = ref MemoryMarshal.GetReference(propertyName);
                    if (IntegerMarshal.ReadUInt32(ref propertyNameRef) == keys /* keys */)
                    {
                        if (reader.Read() && reader.TokenType is JsonTokenType.StartArray)
                        {
                            while (reader.Read() && reader.TokenType is JsonTokenType.StartObject)
                            {
                                Jwk jwk = Jwk.FromJsonReader(ref reader);
                                jwks.Add(jwk);
                            }

                            if (!(reader.TokenType is JsonTokenType.EndArray) || !reader.Read())
                            {
                                ThrowHelper.ThrowInvalidOperationException_MalformedJwks();
                            }
                        }
                    }
                }
            }
        /// <summary>Parses the <see cref="ReadOnlySpan{T}"/> into its <see cref="KeyManagementAlgorithm"/> representation.</summary>
        public static bool TryParse(ReadOnlySpan <byte> value, [NotNullWhen(true)] out KeyManagementAlgorithm?algorithm)
        {
            switch (value.Length)
            {
            case 3 when IntegerMarshal.ReadUInt24(value) == _dir:
                algorithm = Dir;

                goto Found;

            case 6 when IntegerMarshal.ReadUInt16(value, 4) == _KW:
                switch (IntegerMarshal.ReadUInt32(value))
                {
                case _A128:
                    algorithm = A128KW;
                    goto Found;

                case _A192:
                    algorithm = A192KW;
                    goto Found;

                case _A256:
                    algorithm = A256KW;
                    goto Found;
                }

                break;

            case 6 when IntegerMarshal.ReadUInt32(value) == _RSA1 && IntegerMarshal.ReadUInt16(value, 4) == __5:
                algorithm = Rsa1_5;

                goto Found;

            case 7 when IntegerMarshal.ReadUInt56(value) == _ECDH_ES:
                algorithm = EcdhEs;

                goto Found;

            case 8 when IntegerMarshal.ReadUInt64(value) == _RSA_OAEP:
                algorithm = RsaOaep;

                goto Found;

            case 9 when IntegerMarshal.ReadUInt8(value) == (byte) 'A':
                switch (IntegerMarshal.ReadUInt64(value, 1))
                {
                case __128GCMKW:
                    algorithm = A128GcmKW;
                    goto Found;

                case __192GCMKW:
                    algorithm = A192GcmKW;
                    goto Found;

                case __256GCMKW:
                    algorithm = A256GcmKW;
                    goto Found;
                }

                break;

            case 12 when IntegerMarshal.ReadUInt64(value) == _RSA_OAEP:
                switch (IntegerMarshal.ReadUInt32(value, 8))
                {
                case __256:
                    algorithm = RsaOaep256;
                    goto Found;

                case __384:
                    algorithm = RsaOaep384;
                    goto Found;

                case __512:
                    algorithm = RsaOaep512;
                    goto Found;
                }

                break;

            case 14 when IntegerMarshal.ReadUInt64(value) == _ECDH_ES_:
                switch (IntegerMarshal.ReadUInt64(value, 6))
                {
                case _S_A128KW:
                    algorithm = EcdhEsA128KW;
                    goto Found;

                case _S_A192KW:
                    algorithm = EcdhEsA192KW;
                    goto Found;

                case _S_A256KW:
                    algorithm = EcdhEsA256KW;
                    goto Found;
                }

                break;

            // 'PBES2-HS384+A192KW'
            case 18 when IntegerMarshal.ReadUInt64(value) == 6001096197639848528uL &&  /* PBES2-HS 384+A192KW*/
                IntegerMarshal.ReadUInt16(value, 16) == _KW:
                switch (IntegerMarshal.ReadUInt64(value, 8))
                {
                case 4049353170927105330uL:
                    algorithm = Pbes2HS256A128KW;
                    goto Found;

                case 3618977931536382003uL:
                    algorithm = Pbes2HS384A192KW;
                    goto Found;

                case 3906083507292746037:
                    algorithm = Pbes2HS512A256KW;
                    goto Found;
                }

                break;

            // Special case for escaped 'ECDH-ES\u002bAxxxKW'
            case 19 when IntegerMarshal.ReadUInt64(value) == _ECDH_ES_UTF8 /* ECDH-ES\ */:
                switch (IntegerMarshal.ReadUInt64(value, 8) | u002bUpperMask)
                {
                case _u002bA12 when IntegerMarshal.ReadUInt32(value, 15) == __28KW:
                    algorithm = EcdhEsA128KW;

                    goto Found;

                case _u002bA19 when IntegerMarshal.ReadUInt32(value, 15) == __92KW:
                    algorithm = EcdhEsA192KW;

                    goto Found;

                case _u002bA25 when IntegerMarshal.ReadUInt32(value, 15) == __56KW:
                    algorithm = EcdhEsA256KW;

                    goto Found;
                }

                break;
            }

            algorithm = null;
            return(false);

            Found:
            return(true);
        }
예제 #4
0
        /// <summary>
        /// Cast the <see cref="ReadOnlySpan{T}"/> into its <see cref="KeyManagementAlgorithm"/> representation.
        /// </summary>
        /// <param name="value"></param>
        /// <param name="algorithm"></param>
        public static bool TryParse(ReadOnlySpan <byte> value, [NotNullWhen(true)] out KeyManagementAlgorithm?algorithm)
        {
            switch (value.Length)
            {
            case 3 when IntegerMarshal.ReadUInt24(value) == dir:
                algorithm = Direct;

                return(true);

            case 6 when IntegerMarshal.ReadUInt16(value, 4) == KW:
                switch (IntegerMarshal.ReadUInt32(value))
                {
                case A128:
                    algorithm = Aes128KW;
                    return(true);

                case A192:
                    algorithm = Aes192KW;
                    return(true);

                case A256:
                    algorithm = Aes256KW;
                    return(true);
                }

                break;

            case 6 when IntegerMarshal.ReadUInt32(value) == RSA1 && IntegerMarshal.ReadUInt16(value, 4) == _5:
                algorithm = RsaPkcs1;

                return(true);

            case 7 when IntegerMarshal.ReadUInt56(value) == ECDH_ES:
                algorithm = EcdhEs;

                return(true);

            case 8 when IntegerMarshal.ReadUInt64(value) == RSA_OAEP:
                algorithm = RsaOaep;

                return(true);

            case 9 when IntegerMarshal.ReadUInt8(value) == (byte) 'A':
                switch (IntegerMarshal.ReadUInt64(value, 1))
                {
                case _128GCMKW:
                    algorithm = Aes128GcmKW;
                    return(true);

                case _192GCMKW:
                    algorithm = Aes192GcmKW;
                    return(true);

                case _256GCMKW:
                    algorithm = Aes256GcmKW;
                    return(true);
                }

                break;

            case 12 when IntegerMarshal.ReadUInt64(value) == RSA_OAEP:
                switch (IntegerMarshal.ReadUInt32(value, 8))
                {
                case _256:
                    algorithm = RsaOaep256;
                    return(true);

                case _384:
                    algorithm = RsaOaep384;
                    return(true);

                case _512:
                    algorithm = RsaOaep512;
                    return(true);
                }

                break;

            case 14 when IntegerMarshal.ReadUInt64(value) == ECDH_ES_:
                switch (IntegerMarshal.ReadUInt64(value, 6))
                {
                case S_A128KW:
                    algorithm = EcdhEsAes128KW;
                    return(true);

                case S_A192KW:
                    algorithm = EcdhEsAes192KW;
                    return(true);

                case S_A256KW:
                    algorithm = EcdhEsAes256KW;
                    return(true);
                }

                break;

            // Special case for escaped 'ECDH-ES\u002bAxxxKW'
            case 19 when IntegerMarshal.ReadUInt64(value) == ECDH_ES_UTF8 /* ECDH-ES\ */:
                switch (IntegerMarshal.ReadUInt64(value, 8))
                {
                case u002bA12 when IntegerMarshal.ReadUInt32(value, 15) == _28KW:
                    algorithm = EcdhEsAes128KW;

                    return(true);

                case u002bA19 when IntegerMarshal.ReadUInt32(value, 15) == _92KW:
                    algorithm = EcdhEsAes192KW;

                    return(true);

                case u002bA25 when IntegerMarshal.ReadUInt32(value, 15) == _56KW:
                    algorithm = EcdhEsAes256KW;

                    return(true);
                }

                break;
            }

            algorithm = null;
            return(false);
        }
예제 #5
0
        /// <summary>Parses the <see cref="ReadOnlySpan{T}"/> into its <see cref="SignatureAlgorithm"/> representation.</summary>
        public static bool TryParse(ReadOnlySpan <byte> value, [NotNullWhen(true)] out SignatureAlgorithm?algorithm)
        {
            if (value.Length == 5)
            {
                var first = IntegerMarshal.ReadUInt8(value);
                switch (IntegerMarshal.ReadUInt32(value, 1))
                {
                case _S256 when first == (byte)'H':
                    algorithm = HS256;
                    goto Found;

                case _S256 when first == (byte)'R':
                    algorithm = RS256;
                    goto Found;

                case _S256 when first == (byte)'E':
                    algorithm = ES256;
                    goto Found;

                case _S256 when first == (byte)'P':
                    algorithm = PS256;
                    goto Found;

                case _S384 when first == (byte)'H':
                    algorithm = HS384;
                    goto Found;

                case _S384 when first == (byte)'R':
                    algorithm = RS384;
                    goto Found;

                case _S384 when first == (byte)'E':
                    algorithm = ES384;
                    goto Found;

                case _S384 when first == (byte)'P':
                    algorithm = PS384;
                    goto Found;

                case _S512 when first == (byte)'H':
                    algorithm = HS512;
                    goto Found;

                case _S512 when first == (byte)'R':
                    algorithm = RS512;
                    goto Found;

                case _S512 when first == (byte)'E':
                    algorithm = ES512;
                    goto Found;

                case _S512 when first == (byte)'P':
                    algorithm = PS512;
                    goto Found;
                }
            }
            else if (value.Length == 4 && IntegerMarshal.ReadUInt32(value) == _none)
            {
                algorithm = None;
                goto Found;
            }
            else if (value.Length == 6 && IntegerMarshal.ReadUInt48(value) == _ES256K)
            {
                algorithm = ES256K;
                goto Found;
            }

#if NET5_0_OR_GREATER
            Unsafe.SkipInit(out algorithm);
#else
            algorithm = default;
#endif
            return(false);

            Found:
            return(true);
        }
예제 #6
0
        internal static bool TryParseHeader(ReadOnlyMemory <byte> utf8Payload, byte[]?buffer, TokenValidationPolicy policy, [NotNullWhen(true)] out JwtHeaderDocument?header, [NotNullWhen(false)] out TokenValidationError?error)
        {
            ReadOnlySpan <byte> utf8JsonSpan = utf8Payload.Span;
            var database = new JsonMetadata(utf8Payload.Length);
            int algIdx   = -1;
            int encIdx   = -1;
            int kidIdx   = -1;
            int critIdx  = -1;

            var reader = new Utf8JsonReader(utf8JsonSpan);

            if (reader.Read())
            {
                JsonTokenType tokenType = reader.TokenType;
                if (tokenType == JsonTokenType.StartObject)
                {
                    while (reader.Read())
                    {
                        tokenType = reader.TokenType;
                        int tokenStart = (int)reader.TokenStartIndex;

                        if (tokenType == JsonTokenType.EndObject)
                        {
                            break;
                        }
                        else if (tokenType != JsonTokenType.PropertyName)
                        {
                            error = TokenValidationError.MalformedToken();
                            goto Error;
                        }

                        // Adding 1 to skip the start quote will never overflow
                        Debug.Assert(tokenStart < int.MaxValue);

                        database.Append(JsonTokenType.PropertyName, tokenStart + 1, reader.ValueSpan.Length);
                        if (reader.ValueSpan.IndexOf((byte)'\\') != -1)
                        {
                            database.SetNeedUnescaping(database.Length - JsonRow.Size);
                        }

                        ReadOnlySpan <byte> memberName = reader.ValueSpan;

                        reader.Read();
                        tokenType  = reader.TokenType;
                        tokenStart = (int)reader.TokenStartIndex;

                        // Since the input payload is contained within a Span,
                        // token start index can never be larger than int.MaxValue (i.e. utf8JsonSpan.Length).
                        Debug.Assert(reader.TokenStartIndex <= int.MaxValue);
                        if (tokenType == JsonTokenType.String)
                        {
                            if (memberName.Length == 3)
                            {
                                switch ((JwtHeaderParameters)IntegerMarshal.ReadUInt24(memberName))
                                {
                                case JwtHeaderParameters.Alg:
                                    algIdx = database.Length;
                                    break;

                                case JwtHeaderParameters.Enc:
                                    encIdx = database.Length;
                                    break;

                                case JwtHeaderParameters.Kid:
                                    kidIdx = database.Length;
                                    break;
                                }
                            }

                            // Adding 1 to skip the start quote will never overflow
                            Debug.Assert(tokenStart < int.MaxValue);
                            database.Append(JsonTokenType.String, tokenStart + 1, reader.ValueSpan.Length);
                        }
                        else if (tokenType == JsonTokenType.StartObject)
                        {
                            int count    = Utf8JsonReaderHelper.SkipObject(ref reader);
                            int index    = database.Length;
                            int tokenEnd = (int)reader.TokenStartIndex;
                            database.Append(JsonTokenType.StartObject, tokenStart, tokenEnd - tokenStart + 1);
                            database.SetNumberOfRows(index, count);
                        }
                        else if (tokenType == JsonTokenType.StartArray)
                        {
                            int count;
                            if (memberName.Length == 4 &&
                                (JwtHeaderParameters)IntegerMarshal.ReadUInt32(memberName) == JwtHeaderParameters.Crit &&
                                !policy.IgnoreCriticalHeader)
                            {
                                critIdx = database.Length;
                                if (!TryCheckCrit(ref reader, out count))
                                {
                                    error = TokenValidationError.MalformedToken("The 'crit' header parameter must be an array of string.");
                                    goto Error;
                                }
                            }
                            else
                            {
                                count = Utf8JsonReaderHelper.SkipArray(ref reader);
                            }

                            int index    = database.Length;
                            int tokenEnd = (int)reader.TokenStartIndex;
                            database.Append(JsonTokenType.StartArray, tokenStart, tokenEnd - tokenStart + 1);
                            database.SetNumberOfRows(index, count);
                        }
                        else
                        {
                            Debug.Assert(tokenType >= JsonTokenType.Number && tokenType <= JsonTokenType.Null);
                            database.Append(tokenType, tokenStart, reader.ValueSpan.Length);
                        }
                    }
                }
            }

            Debug.Assert(reader.BytesConsumed == utf8JsonSpan.Length);
            database.CompleteAllocations();

            header = new JwtHeaderDocument(new JwtDocument(utf8Payload, database, buffer), algIdx, encIdx, kidIdx, critIdx);
#if NET5_0_OR_GREATER
            Unsafe.SkipInit(out error);
#else
            error = default;
#endif
            return(true);

Error:
#if NET5_0_OR_GREATER
            Unsafe.SkipInit(out header);
#else
            header = default;
#endif
            return(false);
        }
예제 #7
0
        /// <summary>
        /// Parses the <see cref="ReadOnlySpan{T}"/> into its <see cref="SignatureAlgorithm"/> representation.
        /// </summary>
        /// <param name="value"></param>
        /// <param name="algorithm"></param>
        public static bool TryParse(ReadOnlySpan <byte> value, [NotNullWhen(true)] out SignatureAlgorithm?algorithm)
        {
            if (value.Length == 5)
            {
                var first = IntegerMarshal.ReadUInt8(value);
                switch (IntegerMarshal.ReadUInt32(value, 1))
                {
                case S256 when first == (byte)'H':
                    algorithm = HmacSha256;
                    return(true);

                case S256 when first == (byte)'R':
                    algorithm = RsaSha256;
                    return(true);

                case S256 when first == (byte)'E':
                    algorithm = EcdsaSha256;
                    return(true);

                case S256 when first == (byte)'P':
                    algorithm = RsaSsaPssSha256;
                    return(true);

                case S384 when first == (byte)'H':
                    algorithm = HmacSha384;
                    return(true);

                case S384 when first == (byte)'R':
                    algorithm = RsaSha384;
                    return(true);

                case S384 when first == (byte)'E':
                    algorithm = EcdsaSha384;
                    return(true);

                case S384 when first == (byte)'P':
                    algorithm = RsaSsaPssSha384;
                    return(true);

                case S512 when first == (byte)'H':
                    algorithm = HmacSha512;
                    return(true);

                case S512 when first == (byte)'R':
                    algorithm = RsaSha512;
                    return(true);

                case S512 when first == (byte)'E':
                    algorithm = EcdsaSha512;
                    return(true);

                case S512 when first == (byte)'P':
                    algorithm = RsaSsaPssSha512;
                    return(true);
                }
            }
            else if (value.Length == 4 && IntegerMarshal.ReadUInt32(value) == none)
            {
                algorithm = None;
                return(true);
            }

            algorithm = null;
            return(false);
        }
예제 #8
0
        /// <summary>
        /// Parses the UTF-8 <paramref name="buffer"/> as JSON and returns a <see cref="JwtHeader"/>.
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="policy"></param>
        public static JwtHeader ParseHeader(ReadOnlySpan <byte> buffer, TokenValidationPolicy policy)
        {
            Utf8JsonReader reader = new Utf8JsonReader(buffer, isFinalBlock: true, state: default);

            if (!reader.Read() || reader.TokenType != JsonTokenType.StartObject)
            {
                ThrowHelper.ThrowFormatException_MalformedJson();
            }

            var header = new JwtHeader();

            while (reader.Read())
            {
                if (!(reader.TokenType is JsonTokenType.PropertyName))
                {
                    break;
                }

                var name = reader.ValueSpan /* reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan */;
                reader.Read();
                var type = reader.TokenType;


                if (name.Length == 3)
                {
                    if (reader.TokenType == JsonTokenType.String)
                    {
                        var refName = IntegerMarshal.ReadUInt24(name);
                        switch (refName)
                        {
                        case Alg:
                            var alg = reader.ValueSpan /* reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan */;
                            if (SignatureAlgorithm.TryParse(alg, out var signatureAlgorithm))
                            {
                                header.SignatureAlgorithm = signatureAlgorithm;
                            }
                            else if (KeyManagementAlgorithm.TryParse(alg, out var keyManagementAlgorithm))
                            {
                                header.KeyManagementAlgorithm = keyManagementAlgorithm;
                            }
                            else if (SignatureAlgorithm.TryParseSlow(ref reader, out signatureAlgorithm))
                            {
                                header.SignatureAlgorithm = signatureAlgorithm;
                            }
                            else if (KeyManagementAlgorithm.TryParseSlow(ref reader, out keyManagementAlgorithm))
                            {
                                header.KeyManagementAlgorithm = keyManagementAlgorithm;
                            }
                            else
                            {
                                header.SignatureAlgorithm = SignatureAlgorithm.Create(reader.GetString());
                            }

                            continue;

                        case Enc:
                            var enc = reader.ValueSpan /* reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan */;
                            if (EncryptionAlgorithm.TryParse(enc, out var encryptionAlgorithm))
                            {
                                header.EncryptionAlgorithm = encryptionAlgorithm;
                            }
                            else if (EncryptionAlgorithm.TryParseSlow(ref reader, out encryptionAlgorithm))
                            {
                                header.EncryptionAlgorithm = encryptionAlgorithm;
                            }
                            else
                            {
                                header.EncryptionAlgorithm = EncryptionAlgorithm.Create(reader.GetString());
                            }

                            continue;

                        case Zip:
                            var zip = reader.ValueSpan /* reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan */;
                            if (CompressionAlgorithm.TryParse(zip, out var compressionAlgorithm))
                            {
                                header.CompressionAlgorithm = compressionAlgorithm;
                            }
                            else if (CompressionAlgorithm.TryParseSlow(ref reader, out compressionAlgorithm))
                            {
                                header.CompressionAlgorithm = compressionAlgorithm;
                            }
                            else
                            {
                                header.CompressionAlgorithm = CompressionAlgorithm.Create(reader.GetString());
                            }

                            continue;

                        case Cty:
                            header.Cty = reader.GetString();
                            continue;

                        case Typ:
                            header.Typ = reader.GetString();
                            continue;

                        case Kid:
                            header.Kid = reader.GetString();
                            continue;
                        }
                    }
                }
                else if (name.Length == 4)
                {
                    if (reader.TokenType == JsonTokenType.StartArray && IntegerMarshal.ReadUInt32(name) == Crit)
                    {
                        var handlers = policy.CriticalHandlers;
                        if (handlers.Count != 0)
                        {
                            var criticalHeaderHandlers = new List <KeyValuePair <string, ICriticalHeaderHandler> >(handlers.Count);
                            var criticals = new List <JwtValue>();
                            while (reader.Read() && reader.TokenType == JsonTokenType.String)
                            {
                                string criticalHeader = reader.GetString();
                                criticals.Add(new JwtValue(criticalHeader));
                                if (handlers.TryGetValue(criticalHeader, out var handler))
                                {
                                    criticalHeaderHandlers.Add(new KeyValuePair <string, ICriticalHeaderHandler>(criticalHeader, handler));
                                }
                                else
                                {
                                    criticalHeaderHandlers.Add(new KeyValuePair <string, ICriticalHeaderHandler>(criticalHeader, null !));
                                }
                            }

                            header.CriticalHeaderHandlers = criticalHeaderHandlers;

                            if (reader.TokenType != JsonTokenType.EndArray)
                            {
                                ThrowHelper.ThrowFormatException_MalformedJson("The 'crit' header parameter must be an array of string.");
                            }

                            header.Inner.Add(name, new JwtArray(criticals));
                        }
                        else
                        {
                            var criticals = new List <JwtValue>();
                            while (reader.Read() && reader.TokenType == JsonTokenType.String)
                            {
                                string criticalHeader = reader.GetString();
                                criticals.Add(new JwtValue(criticalHeader));
                            }

                            if (reader.TokenType != JsonTokenType.EndArray)
                            {
                                ThrowHelper.ThrowFormatException_MalformedJson("The 'crit' header parameter must be an array of string.");
                            }

                            header.Inner.Add(name, new JwtArray(criticals));
                        }

                        continue;
                    }
                }


                switch (type)
                {
                case JsonTokenType.StartObject:
                    header.Inner.Add(name, JsonParser.ReadJsonObject(ref reader));
                    break;

                case JsonTokenType.StartArray:
                    header.Inner.Add(name, JsonParser.ReadJsonArray(ref reader));
                    break;

                case JsonTokenType.String:
                    header.Inner.Add(name, reader.GetString());
                    break;

                case JsonTokenType.True:
                    header.Inner.Add(name, true);
                    break;

                case JsonTokenType.False:
                    header.Inner.Add(name, false);
                    break;

                case JsonTokenType.Null:
                    header.Inner.Add(name);
                    break;

                case JsonTokenType.Number:
                    if (reader.TryGetInt64(out long longValue))
                    {
                        header.Inner.Add(name, longValue);
                    }
                    else
                    {
                        header.Inner.Add(name, reader.GetDouble());
                    }
                    break;

                default:
                    ThrowHelper.ThrowFormatException_MalformedJson();
                    break;
                }
            }

            if (!(reader.TokenType is JsonTokenType.EndObject))
            {
                ThrowHelper.ThrowFormatException_MalformedJson();
            }

            return(header);
        }
예제 #9
0
        /// <summary>Parses the <see cref="ReadOnlySpan{T}"/> into its <see cref="SignatureAlgorithm"/> representation.</summary>
        /// <param name="value"></param>
        /// <param name="algorithm"></param>
        public static bool TryParse(ReadOnlySpan <byte> value, [NotNullWhen(true)] out SignatureAlgorithm?algorithm)
        {
            if (value.Length == 5)
            {
                var first = IntegerMarshal.ReadUInt8(value);
                switch (IntegerMarshal.ReadUInt32(value, 1))
                {
                case _S256 when first == (byte)'H':
                    algorithm = HS256;
                    goto Found;

                case _S256 when first == (byte)'R':
                    algorithm = RS256;
                    goto Found;

                case _S256 when first == (byte)'E':
                    algorithm = ES256;
                    goto Found;

                case _S256 when first == (byte)'P':
                    algorithm = PS256;
                    goto Found;

                case _S384 when first == (byte)'H':
                    algorithm = HS384;
                    goto Found;

                case _S384 when first == (byte)'R':
                    algorithm = RS384;
                    goto Found;

                case _S384 when first == (byte)'E':
                    algorithm = ES384;
                    goto Found;

                case _S384 when first == (byte)'P':
                    algorithm = PS384;
                    goto Found;

                case _S512 when first == (byte)'H':
                    algorithm = HS512;
                    goto Found;

                case _S512 when first == (byte)'R':
                    algorithm = RS512;
                    goto Found;

                case _S512 when first == (byte)'E':
                    algorithm = ES512;
                    goto Found;

                case _S512 when first == (byte)'P':
                    algorithm = PS512;
                    goto Found;
                }
            }
            else if (value.Length == 4 && IntegerMarshal.ReadUInt32(value) == _none)
            {
                algorithm = None;
                goto Found;
            }
            else if (value.Length == 6 && IntegerMarshal.ReadUInt48(value) == _ES256X)
            {
                algorithm = ES256X;
                goto Found;
            }

            algorithm = null;
            return(false);

            Found:
            return(true);
        }