public void EnumerateObjects() { JwtHeaderDocument.TryParseHeader(Utf8.GetBytes("{\"object\":{\"p1\":1, \"p2\":{}, \"p3\":{\"x\":true}, \"p4\":true, \"p5\":false, \"p6\":null, \"p7\":\"text\", \"p8\":[], \"p8\":[true, false]}}"), null, TokenValidationPolicy.NoValidation, out var header, out _); header.TryGetHeaderParameter("object", out var element); var enumerator = element.EnumerateObject(); enumerator.MoveNext(); Assert.Equal(JsonValueKind.Number, enumerator.Current.Value.ValueKind); enumerator.MoveNext(); Assert.Equal(JsonValueKind.Object, enumerator.Current.Value.ValueKind); enumerator.MoveNext(); Assert.Equal(JsonValueKind.Object, enumerator.Current.Value.ValueKind); enumerator.MoveNext(); Assert.Equal(JsonValueKind.True, enumerator.Current.Value.ValueKind); enumerator.MoveNext(); Assert.Equal(JsonValueKind.False, enumerator.Current.Value.ValueKind); enumerator.MoveNext(); Assert.Equal(JsonValueKind.Null, enumerator.Current.Value.ValueKind); enumerator.MoveNext(); Assert.Equal(JsonValueKind.String, enumerator.Current.Value.ValueKind); enumerator.MoveNext(); Assert.Equal(JsonValueKind.Array, enumerator.Current.Value.ValueKind); enumerator.MoveNext(); Assert.Equal(JsonValueKind.Array, enumerator.Current.Value.ValueKind); }
public void EnumerateObjects_NoAnObject_Fail() { JwtHeaderDocument.TryParseHeader(Utf8.GetBytes("{\"object\":[1, 2, 3, 4, 5]}"), null, TokenValidationPolicy.NoValidation, out var header, out _); header.TryGetHeaderParameter("object", out var element); Assert.Throws <InvalidOperationException>(() => element.EnumerateObject()); }
public void AddHeader_Parallel() { var cache = new LruJwtHeaderDocumentCache(); var rawHeaders = new byte[1000][]; for (int i = 0; i < 1000; i++) { rawHeaders[i] = new byte[32]; FillRandom(rawHeaders[i]); } JwtHeaderDocument.TryParseHeader(Encoding.UTF8.GetBytes($"{{\"kid\":\"{0}\"}}"), null, TokenValidationPolicy.NoValidation, out JwtHeaderDocument header, out var error); var p = Parallel.For(0, 100, j => { for (int i = 0; i < 1000; i++) { cache.AddHeader(rawHeaders[i], header.Clone()); } }); Assert.True(cache.Validate()); var p2 = Parallel.For(0, 100, j => { for (int i = 0; i < 1000; i++) { cache.TryGetHeader(rawHeaders[i], out var header); } }); Assert.True(cache.Validate()); }
public void AddHeader_BeyondCapacity() { const int Count = 20; var cache = new LruJwtHeaderDocumentCache(); var rawHeaders = new byte[Count][]; for (int i = 0; i < Count; i++) { rawHeaders[i] = new byte[32]; FillRandom(rawHeaders[i]); JwtHeaderDocument.TryParseHeader(Encoding.UTF8.GetBytes($"{{\"kid\":\"{i}\"}}"), null, TokenValidationPolicy.NoValidation, out JwtHeaderDocument header, out var error); cache.AddHeader(rawHeaders[i], header); Assert.NotNull(cache.Head); Assert.Equal(header.Alg.ToString(), cache.Head.Alg.ToString()); Assert.Equal(header.Kid.ToString(), cache.Head.Kid.ToString()); } Assert.Equal("19", cache.Head.Kid.ToString()); Assert.Equal("4", cache.Tail.Kid.ToString()); for (int i = 0; i < 4; i++) { Assert.False(cache.TryGetHeader(rawHeaders[i], out var header)); } for (int i = 4; i < Count; i++) { Assert.True(cache.TryGetHeader(rawHeaders[i], out var header)); } }
public void EnumerateArrayOfObject() { JwtHeaderDocument.TryParseHeader(Utf8.GetBytes("{\"array\":[ 1, {}, {\"x\":true}, true, false, null, \"text\", [], [true, false]]}"), null, TokenValidationPolicy.NoValidation, out var header, out _); header.TryGetHeaderParameter("array", out var element); var enumerator = element.EnumerateArray(); enumerator.MoveNext(); Assert.Equal(JsonValueKind.Number, enumerator.Current.ValueKind); enumerator.MoveNext(); Assert.Equal(JsonValueKind.Object, enumerator.Current.ValueKind); enumerator.MoveNext(); Assert.Equal(JsonValueKind.Object, enumerator.Current.ValueKind); enumerator.MoveNext(); Assert.Equal(JsonValueKind.True, enumerator.Current.ValueKind); enumerator.MoveNext(); Assert.Equal(JsonValueKind.False, enumerator.Current.ValueKind); enumerator.MoveNext(); Assert.Equal(JsonValueKind.Null, enumerator.Current.ValueKind); enumerator.MoveNext(); Assert.Equal(JsonValueKind.String, enumerator.Current.ValueKind); enumerator.MoveNext(); Assert.Equal(JsonValueKind.Array, enumerator.Current.ValueKind); enumerator.MoveNext(); Assert.Equal(JsonValueKind.Array, enumerator.Current.ValueKind); }
public void EnumerateArrayOfInteger_NotAnArray_Fail() { JwtHeaderDocument.TryParseHeader(Utf8.GetBytes("{\"array\":{\"x\":1}}"), null, TokenValidationPolicy.NoValidation, out var header, out _); header.TryGetHeaderParameter("array", out var element); Assert.Throws <InvalidOperationException>(() => element.EnumerateArray <long>()); }
public void GetKeys_CachedButExpired_ReturnsRefreshedKeys() { var provider = new JwksHttpKeyProvider("https://example.com", "https://example.com/jwks", new TestHttpMessageHandler { Responses = new[] { new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent("{\"keys\":[]}", Encoding.UTF8, "application/json") }, new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent("{\"keys\":[{\"kty\":\"RSA\",\"kid\":\"1234\",\"e\":\"AQAB\",\"n\":\"n6fNIStd3luK2mvco0ZnkDGE4JxB2FLmYtVJNyTmMfOj7CR5oM7vHSuOQYe17c8CUXBSCed5i6CmUyI59Vj4D2D2zdzqMiIyA5Y0djw5Js04QSvbXZId25YgMoHU0dichI1MmUYMPk5iQ_SwmSXsJKxwk1ytd1DciMxpCWkkAwJCAMoYR0_wcrtLX0M3i1sJthpCKle0-bj5YnhVE85vGeVrkvs9b8CKUCwqGruNptHtebpMKR1rBx1QXBTHHhXJjk5XQLu_S9_URuD0M6j__liGcjYzFEiz6b9NAjHHrraPfDfuKIgnHwpLFA-J8zjZeoXBstr9Mut_Gsgqmxg_cQ\",\"alg\":\"RS256\"}]}", Encoding.UTF8, "application/json") } } }, automaticRefreshInterval: 0); JwtHeaderDocument.TryParseHeader(Encoding.UTF8.GetBytes("{\"kid\":\"1234\"}"), null, TokenValidationPolicy.NoValidation, out var header, out _); var keys = provider.GetKeys(header); Assert.Empty(keys); keys = provider.GetKeys(header); Assert.Single(keys); Assert.Equal("1234", keys[0].Kid.ToString()); }
public void Unwrap2() { var kwp = new EcdhKeyWrapper(_bobKey, EncryptionAlgorithm.A128CbcHS256, KeyManagementAlgorithm.EcdhEsA128KW); byte[] wrappedKey = new byte[kwp.GetKeyWrapSize()]; var header = new JwtHeader { { JwtHeaderParameterNames.Apu, Utf8.GetString(Base64Url.Encode("Alice")) }, { JwtHeaderParameterNames.Apv, Utf8.GetString(Base64Url.Encode("Bob")) } }; kwp.WrapKey(_aliceKey, header, wrappedKey); var kuwp = new EcdhKeyUnwrapper(_bobKey, EncryptionAlgorithm.A128CbcHS256, KeyManagementAlgorithm.EcdhEsA128KW); var apu = Encoding.UTF8.GetString(Base64Url.Encode("Alice"));; var apv = Encoding.UTF8.GetString(Base64Url.Encode("Bob")); header.TryGetValue(JwtHeaderParameterNames.Epk, out var epkElement); var epk = (Jwk)epkElement.Value; var parsed = JwtHeaderDocument.TryParseHeader(Encoding.UTF8.GetBytes($"{{\"apu\":\"{apu}\",\"apv\":\"{apv}\",\"epk\":{epk}}}"), null, TokenValidationPolicy.NoValidation, out var jwtHeader, out var error); Assert.True(parsed); byte[] unwrappedKey = new byte[kuwp.GetKeyUnwrapSize(wrappedKey.Length)]; var unwrapped = kuwp.TryUnwrapKey(wrappedKey, unwrappedKey, jwtHeader, out int bytesWritten); Assert.True(unwrapped); }
public void Unwrap() { var staticKey = new byte[] { 111, 27, 25, 52, 66, 29, 20, 78, 92, 176, 56, 240, 65, 208, 82, 112, 161, 131, 36, 55, 202, 236, 185, 172, 129, 23, 153, 194, 195, 48, 253, 182 }; var parsed = JwtHeaderDocument.TryParseHeader(Encoding.UTF8.GetBytes($"{{}}"), null, TokenValidationPolicy.NoValidation, out var jwtHeader, out var error); Assert.True(parsed); var kuwp = new DirectKeyUnwrapper(SymmetricJwk.FromByteArray(staticKey), EncryptionAlgorithm.A128CbcHS256, KeyManagementAlgorithm.Dir); byte[] unwrappedKey = new byte[kuwp.GetKeyUnwrapSize(staticKey.Length)]; var unwrapped = kuwp.TryUnwrapKey(default, unwrappedKey, jwtHeader, out _);
public void Unwrap() { var expectedStaticKey = new byte[] { 111, 27, 25, 52, 66, 29, 20, 78, 92, 176, 56, 240, 65, 208, 82, 112, 161, 131, 36, 55, 202, 236, 185, 172, 129, 23, 153, 194, 195, 48, 253, 182 }; var wrappedKey = new byte[] { 78, 186, 151, 59, 11, 141, 81, 240, 213, 245, 83, 211, 53, 188, 134, 188, 66, 125, 36, 200, 222, 124, 5, 103, 249, 52, 117, 184, 140, 81, 246, 158, 161, 177, 20, 33, 245, 57, 59, 4 }; var parsed = JwtHeaderDocument.TryParseHeader(Encoding.UTF8.GetBytes($"{{\"p2s\":\"2WCTcJZ1Rvd_CJuJripQ1w\",\"p2c\":4096}}"), null, TokenValidationPolicy.NoValidation, out var jwtHeader, out var error); Assert.True(parsed); var kuwp = new Pbes2KeyUnwrapper(PasswordBasedJwk.FromPassphrase(_password), EncryptionAlgorithm.A128CbcHS256, KeyManagementAlgorithm.Pbes2HS256A128KW); byte[] unwrappedKey = new byte[kuwp.GetKeyUnwrapSize(wrappedKey.Length)]; var unwrapped = kuwp.TryUnwrapKey(wrappedKey, unwrappedKey, jwtHeader, out _); Assert.True(unwrapped); Assert.Equal(expectedStaticKey, unwrappedKey); }
public void EnumerateArrayOfString() { JwtHeaderDocument.TryParseHeader(Utf8.GetBytes("{\"array\":[\"text1\", \"text2\", \"text3\", \"text4\", \"text5\"]}"), null, TokenValidationPolicy.NoValidation, out var header, out _); header.TryGetHeaderParameter("array", out var element); var enumerator = element.EnumerateArray <string>(); enumerator.MoveNext(); Assert.Equal("text1", enumerator.Current.GetString()); enumerator.MoveNext(); Assert.Equal("text2", enumerator.Current.GetString()); enumerator.MoveNext(); Assert.Equal("text3", enumerator.Current.GetString()); enumerator.MoveNext(); Assert.Equal("text4", enumerator.Current.GetString()); enumerator.MoveNext(); Assert.Equal("text5", enumerator.Current.GetString()); }
public void EnumerateArrayOfInteger() { JwtHeaderDocument.TryParseHeader(Utf8.GetBytes("{\"array\":[1, 2, 3, 4, 5]}"), null, TokenValidationPolicy.NoValidation, out var header, out _); header.TryGetHeaderParameter("array", out var element); var enumerator = element.EnumerateArray <long>(); enumerator.MoveNext(); Assert.Equal(1, enumerator.Current.GetInt64()); enumerator.MoveNext(); Assert.Equal(2, enumerator.Current.GetInt64()); enumerator.MoveNext(); Assert.Equal(3, enumerator.Current.GetInt64()); enumerator.MoveNext(); Assert.Equal(4, enumerator.Current.GetInt64()); enumerator.MoveNext(); Assert.Equal(5, enumerator.Current.GetInt64()); }
public void AddHeader_Lru() { var cache = new LruJwtHeaderDocumentCache(); var rawHeaders = new byte[10][]; for (int i = 0; i < 10; i++) { rawHeaders[i] = new byte[32]; FillRandom(rawHeaders[i]); JwtHeaderDocument.TryParseHeader(Encoding.UTF8.GetBytes($"{{\"kid\":\"{i}\"}}"), null, TokenValidationPolicy.NoValidation, out JwtHeaderDocument header, out var error); cache.AddHeader(rawHeaders[i], header); } for (int i = 0; i < 10; i++) { Assert.True(cache.TryGetHeader(rawHeaders[i], out var header)); Assert.Equal(header, cache.Head); Assert.NotEqual(header, cache.Tail); } }
public void AddHeader() { const int Count = 10; var cache = new LruJwtHeaderDocumentCache(); var rawHeaders = new byte[10][]; for (int i = 0; i < Count; i++) { rawHeaders[i] = new byte[32]; FillRandom(rawHeaders[i]); JwtHeaderDocument.TryParseHeader(Encoding.UTF8.GetBytes($"{{\"kid\":\"{i}\"}}"), null, TokenValidationPolicy.NoValidation, out JwtHeaderDocument header, out var error); cache.AddHeader(rawHeaders[i], header); } Assert.Equal("9", cache.Head.Kid.ToString()); Assert.Equal("0", cache.Tail.Kid.ToString()); for (int i = 0; i < Count; i++) { Assert.True(cache.TryGetHeader(rawHeaders[i], out var header)); } }
/// <summary>Gets the list of <see cref="Jwk"/>.</summary> public Jwk[] GetKeys(JwtHeaderDocument header) { return(_jwks.GetKeys(header.Kid)); }
/// <summary>Unwrap a key.</summary> /// <param name="keyBytes">key to unwrap.</param> /// <param name="destination"></param> /// <param name="header"></param> /// <param name="bytesWritten"></param> /// <returns>Unwrapped key.</returns> public abstract bool TryUnwrapKey(ReadOnlySpan <byte> keyBytes, Span <byte> destination, JwtHeaderDocument header, out int bytesWritten);
/// <inheritsdoc /> public override bool TryUnwrapKey(ReadOnlySpan <byte> key, Span <byte> destination, JwtHeaderDocument header, out int bytesWritten) { Debug.Assert(header != null); if (key.IsEmpty) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); } if (_disposed) { ThrowHelper.ThrowObjectDisposedException(GetType()); } #if SUPPORT_SPAN_CRYPTO #if !NETCOREAPP return(_rsa.TryDecrypt(key, destination, _padding, out bytesWritten)); #else try { // https://github.com/dotnet/corefx/pull/36601 bool decrypted; if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { int keySizeBytes = _rsa.KeySize / 8; // OpenSSL does not take a length value for the destination, so it can write out of bounds. // To prevent the OOB write, decrypt into a temporary buffer. if (destination.Length < keySizeBytes) { Span <byte> tmp = stackalloc byte[0]; byte[]? rent = null; try { // RSA up through 4096 stackalloc if (_rsa.KeySize <= Constants.MaxStackallocBytes * 8 * 2) { tmp = stackalloc byte[Constants.MaxStackallocBytes * 2]; } else { rent = ArrayPool <byte> .Shared.Rent(keySizeBytes); tmp = rent; } decrypted = _rsa.TryDecrypt(key, tmp, _padding, out bytesWritten); if (decrypted) { if (bytesWritten > destination.Length) { decrypted = false; bytesWritten = 0; } else { tmp = tmp.Slice(0, bytesWritten); tmp.CopyTo(destination); } CryptographicOperations.ZeroMemory(tmp); } } finally { if (rent != null) { // Already cleared ArrayPool <byte> .Shared.Return(rent); } } } else { decrypted = _rsa.TryDecrypt(key, destination, _padding, out bytesWritten); } } else { decrypted = _rsa.TryDecrypt(key, destination, _padding, out bytesWritten); } return(decrypted); } catch (CryptographicException) { bytesWritten = 0; return(false); } #endif #else try { var result = _rsa.Decrypt(key.ToArray(), _padding); bytesWritten = result.Length; result.CopyTo(destination); return(true); } catch (CryptographicException) { bytesWritten = 0; return(false); } #endif }
/// <inheritsdoc /> public override bool TryUnwrapKey(ReadOnlySpan <byte> keyBytes, Span <byte> destination, JwtHeaderDocument header, out int bytesWritten) { if (!header.TryGetHeaderParameter(JwtHeaderParameterNames.IV.EncodedUtf8Bytes, out var encodedIV)) { ThrowHelper.ThrowJwtDescriptorException_HeaderIsRequired(JwtHeaderParameterNames.IV); } if (!header.TryGetHeaderParameter(JwtHeaderParameterNames.Tag.EncodedUtf8Bytes, out var encodedTag)) { ThrowHelper.ThrowJwtDescriptorException_HeaderIsRequired(JwtHeaderParameterNames.Tag); } var rawIV = encodedIV.GetRawValue(); Span <byte> nonce = stackalloc byte[IVSize]; var rawTag = encodedTag.GetRawValue(); Span <byte> tag = stackalloc byte[TagSize]; try { Base64Url.Decode(rawIV.Span, nonce); Base64Url.Decode(rawTag.Span, tag); using var aesGcm = new AesGcm(_key.K); if (destination.Length > keyBytes.Length) { destination = destination.Slice(0, keyBytes.Length); } aesGcm.Decrypt(nonce, keyBytes, tag, destination); bytesWritten = destination.Length; return(true); } catch (CryptographicException) { return(ThrowHelper.TryWriteError(out bytesWritten)); } }
/// <inheritdoc/> public void AddHeader(ReadOnlySpan <byte> rawHeader, JwtHeaderDocument header) { _index = (_index + 1) & (MaxItems - 1); _nodes[_index] = new Node(rawHeader.ToArray(), header.Clone()); }
/// <inheritsdoc /> public override bool TryUnwrapKey(ReadOnlySpan <byte> keyBytes, Span <byte> destination, JwtHeaderDocument header, out int bytesWritten) { if (!header.TryGetHeaderParameter(JwtHeaderParameterNames.P2c.EncodedUtf8Bytes, out JwtElement p2c)) { ThrowHelper.ThrowJwtDescriptorException_HeaderIsRequired(JwtHeaderParameterNames.P2c); } if (!header.TryGetHeaderParameter(JwtHeaderParameterNames.P2s.EncodedUtf8Bytes, out JwtElement p2s)) { ThrowHelper.ThrowJwtDescriptorException_HeaderIsRequired(JwtHeaderParameterNames.P2s); } int iterationCount = (int)p2c.GetInt64(); var b64p2s = p2s.GetRawValue(); int p2sLength = Base64Url.GetArraySizeRequiredToDecode(b64p2s.Length); Span <byte> salt = stackalloc byte[p2sLength + 1 + _algorithmNameLength]; Base64Url.Decode(b64p2s.Span, salt.Slice(_algorithmNameLength + 1)); salt[_algorithmNameLength] = 0x00; _algorithm.EncodedUtf8Bytes.CopyTo(salt); Span <byte> derivedKey = stackalloc byte[_keySizeInBytes]; Pbkdf2.DeriveKey(_password, salt, _hashAlgorithm, (uint)iterationCount, derivedKey); using var keyUnwrapper = new AesKeyUnwrapper(derivedKey, EncryptionAlgorithm, _keyManagementAlgorithm); return(keyUnwrapper.TryUnwrapKey(keyBytes, destination, header, out bytesWritten)); }
/// <inheritsdoc /> public override bool TryUnwrapKey(ReadOnlySpan <byte> keyBytes, Span <byte> destination, JwtHeaderDocument header, out int bytesWritten) { if (!header.TryGetHeaderParameter(JwtHeaderParameterNames.Epk.EncodedUtf8Bytes, out var epk)) { ThrowHelper.ThrowJwtDescriptorException_HeaderIsRequired(JwtHeaderParameterNames.Epk); } header.TryGetHeaderParameter(JwtHeaderParameterNames.Apu.EncodedUtf8Bytes, out JwtElement apu); header.TryGetHeaderParameter(JwtHeaderParameterNames.Apv.EncodedUtf8Bytes, out JwtElement apv); byte[] secretAppend = BuildSecretAppend(apu, apv); ReadOnlySpan <byte> exchangeHash; using (var ephemeralKey = ECDiffieHellman.Create(ECJwk.FromJwtElement(epk).ExportParameters())) { var privateKey = _key.CreateEcdhKey(); if (ephemeralKey.KeySize != privateKey.KeySize) { return(ThrowHelper.TryWriteError(out bytesWritten)); } exchangeHash = new ReadOnlySpan <byte>(privateKey.DeriveKeyFromHash(ephemeralKey.PublicKey, _hashAlgorithm, _secretPreprend, secretAppend), 0, _keySizeInBytes); } if (Algorithm.ProduceEncryptionKey) { using var keyUnwrapper = new AesKeyUnwrapper(exchangeHash, EncryptionAlgorithm, _keyManagementAlgorithm !); return(keyUnwrapper.TryUnwrapKey(keyBytes, destination, header, out bytesWritten)); } else { exchangeHash.CopyTo(destination); bytesWritten = destination.Length; return(true); } }
public override bool TryUnwrapKey(ReadOnlySpan <byte> keyBytes, Span <byte> destination, JwtHeaderDocument header, out int bytesWritten) { // Direct key encryption does not support key wrapping if (keyBytes.Length > 0) { bytesWritten = 0; return(false); } _key.K.CopyTo(destination); bytesWritten = _key.K.Length; return(true); }
public Jwk[] GetKeys(JwtHeaderDocument header) { return(GetKeysAsync().GetAwaiter().GetResult()); }
public Node(ReadOnlyMemory <byte> key, JwtHeaderDocument header) { Key = key; Header = header; }