/// <summary>Configure the signature behavior for a specific <paramref name="issuer"/>.</summary> public TokenValidationPolicyBuilder RequireSignature(string issuer, Jwks keys, SignatureAlgorithm defaultAlgorithm) { if (keys is null) { throw new ArgumentNullException(nameof(keys)); } return(RequireSignatureByDefault(issuer, new StaticKeyProvider(keys), defaultAlgorithm)); }
internal static Exception CreateNotSupportedException_Algorithm(SignatureAlgorithm algorithm) => new NotSupportedException($"The algorithm '{algorithm}' is not supported for this kind of JWK.");
/// <inheritsdoc /> protected override SignatureVerifier CreateSignatureVerifier(SignatureAlgorithm algorithm) => throw new NotImplementedException();
private static Exception CreateArgumentOutOfRangeException_InvalidEcdsaKeySize(Jwk key, SignatureAlgorithm algorithm, int validKeySize, int keySize) => new ArgumentOutOfRangeException(nameof(algorithm), $"Invalid key size for '{key.Kid}'. Valid key size must be '{validKeySize}' bits for the algorithm {algorithm}. Key size: '{keySize}'.");
private static Exception CreateNotSupportedException_SignatureAlgorithm(SignatureAlgorithm algorithm, Jwk?key) => new NotSupportedException($"Signature failed. No support for: Algorithm: '{algorithm}', key: '{key?.Kid}'.");
/// <summary>Adds a base64-url encoded header to the cache.</summary> /// <param name="header"></param> /// <param name="alg"></param> /// <param name="kid"></param> /// <param name="typ"></param> /// <param name="base6UrlHeader"></param> public void AddHeader(JwtHeader header, SignatureAlgorithm alg, JsonEncodedText kid, string?typ, ReadOnlySpan <byte> base6UrlHeader) { _firstHeader = new WrappedHeader(header, base6UrlHeader.ToArray()); if (IsEligibleHeaderForJws(header.Count, kid, typ)) { int algorithmId = (int)alg.Id; bool lockTaken = false; try { _spinLock.Enter(ref lockTaken); if (_count >= MaxSize) { Clear(); } var node = _head; while (node != null) { if (algorithmId == node.AlgorithmId) { break; } node = node.Next; } var key = alg.Id; if (node is null) { _count++; node = new Bucket(algorithmId, kid, new CacheEntry(base6UrlHeader.ToArray(), typ)) { Next = _head }; } else { if (!node.Entries.ContainsKey(kid)) { _count++; node.Entries[kid] = new CacheEntry(base6UrlHeader.ToArray(), typ); } } if (!ReferenceEquals(_head, node)) { if (_head != null) { _head.Previous = node; } _head = node; } if (_tail is null) { _tail = node; } } finally { if (lockTaken) { _spinLock.Exit(); } } } }
public void AddHeader(JwtHeader header, SignatureAlgorithm alg, JsonEncodedText kid, string?typ, ReadOnlySpan <byte> base6UrlHeader) { }
public bool TryGetHeader(JwtHeader header, SignatureAlgorithm alg, JsonEncodedText kid, string?typ, [NotNullWhen(true)] out byte[]?base64UrlHeader) { base64UrlHeader = null; return(false); }
/// <summary>Initializes a new instance of <see cref="EncryptionAlgorithm"/>.</summary> public EncryptionAlgorithm(AlgorithmId id, string name, ushort requiredKeySizeInBytes, SignatureAlgorithm signatureAlgorithm, ushort requiredKeyWrappedSizeInBytes, EncryptionType category) { _id = id; _utf8Name = JsonEncodedText.Encode(name); _requiredKeySizeInBytes = requiredKeySizeInBytes; _signatureAlgorithm = signatureAlgorithm; _keyWrappedSizeInBytes = requiredKeyWrappedSizeInBytes; _category = category; _encryptor = CreateAuthenticatedEncryptor(this); _decryptor = CreateAuthenticatedDecryptor(this); }
/// <summary>Configure the signature behavior for a specific <paramref name="issuer"/>.</summary> public TokenValidationPolicyBuilder RequireSignature(string issuer, string jwksUrl, SignatureAlgorithm defaultAlgorithm, HttpMessageHandler?handler = null) => RequireSignatureByDefault(issuer, new JwksHttpKeyProvider(issuer, jwksUrl, handler), defaultAlgorithm);
private static Exception CreateNotSupportedException_KeyedHashAlgorithm(SignatureAlgorithm algorithm) => new NotSupportedException($"Unable to create hash algorithm for algorithm '{algorithm}'.");
/// <summary>Configure the <see cref="TokenValidationPolicy"/> based on the <paramref name="metadataUri"/> /// as defined by https://tools.ietf.org/html/rfc8414 and https://openid.net/specs/openid-connect-discovery-1_0.html.</summary> public TokenValidationPolicyBuilder RequireMetadataConfiguration(string metadataUri, SignatureAlgorithm defaultAlgorithm, HttpMessageHandler?handler = null) { if (!Uri.IsWellFormedUriString(metadataUri, UriKind.Absolute)) { throw new InvalidOperationException($"'{metadataUri}' is not a valid URL."); } var keyProvider = new JwksHttpKeyProvider(metadataUri, handler); return(RequireSignatureByDefault(keyProvider.Issuer !, keyProvider, defaultAlgorithm)); }
/// <summary>Configure the signature behavior for a specific <paramref name="issuer"/>.</summary> public TokenValidationPolicyBuilder RequireSignatureByDefault(string issuer, IKeyProvider keyProvider, SignatureAlgorithm defaultAlgorithm) { if (issuer is null) { throw new ArgumentNullException(nameof(issuer)); } if (keyProvider is null) { throw new ArgumentNullException(nameof(keyProvider)); } if (defaultAlgorithm is null) { throw new ArgumentNullException(nameof(defaultAlgorithm)); } if (defaultAlgorithm == SignatureAlgorithm.None) { throw new ArgumentException($"The algorithm 'none' is not valid with the method {nameof(RequireSignature)}. Use the method {nameof(AcceptUnsecureToken)} instead.", nameof(defaultAlgorithm)); } _hasSignatureValidation = true; var policy = SignatureValidationPolicy.Create(keyProvider, defaultAlgorithm); _signaturePolicies[issuer] = policy; return(this); }
/// <summary>Configure the signature behavior for a specific <paramref name="issuer"/>.</summary> public TokenValidationPolicyBuilder RequireSignature(string issuer, IList <Jwk> keys, SignatureAlgorithm defaultAlgorithm) => RequireSignature(issuer, new Jwks(keys), defaultAlgorithm);
/// <inheritsdoc /> public override bool SupportSignature(SignatureAlgorithm algorithm) => false;
/// <summary>Initializes a new instance of the <see cref="EllipticalCurve"/> struct.</summary> public EllipticalCurve(byte id, ECCurve namedCurve, JsonEncodedText name, int keySizeInBits, int hashSize, SignatureAlgorithm supportedSignatureAlgorithm) { Id = id; KeySizeInBits = keySizeInBits; Name = name; CurveParameters = namedCurve; HashSize = hashSize; SupportedSignatureAlgorithm = supportedSignatureAlgorithm; }
public bool TryGetHeader(JwtHeader header, SignatureAlgorithm alg, JsonEncodedText kid, string?typ, [NotNullWhen(true)] out byte[]?base64UrlHeader) { return(_jwsCache.TryGetHeader(header, alg, kid, typ, out base64UrlHeader)); }
/// <summary> /// Initializes a new instance of the <see cref="Jwk"/> class. /// </summary> /// <param name="alg"></param> protected Jwk(SignatureAlgorithm alg) { Alg = alg.Utf8Name; _signatureAlgorithm = alg; }
public void AddHeader(JwtHeader header, SignatureAlgorithm alg, JsonEncodedText kid, string?typ, ReadOnlySpan <byte> base64UrlHeader) { _jwsCache.AddHeader(header, alg, kid, typ, base64UrlHeader); }
/// <summary>Configure the signature behavior with Key Vault for a specific <paramref name="vaultUri"/>.</summary> public static TokenValidationPolicyBuilder RequireSignatureWithKeyVault(this TokenValidationPolicyBuilder builder, string vaultUri, TokenCredential credentials, SignatureAlgorithm algorithm, long minimumRefreshInterval = CachedKeyProvider.DefaultMinimumRefreshInterval, long automaticRefreshInterval = CachedKeyProvider.DefaultAutomaticRefreshInterval) => builder.RequireSignature(vaultUri, new KeyVaultKeyProvider(vaultUri, credentials, minimumRefreshInterval, automaticRefreshInterval), algorithm);
internal static void ThrowArgumentOutOfRangeException_InvalidEcdsaKeySize(Jwk key, SignatureAlgorithm algorithm, int validKeySize, int keySize) => throw CreateArgumentOutOfRangeException_InvalidEcdsaKeySize(key, algorithm, validKeySize, keySize);
/// <summary>Configure the signature behavior with Key Vault for a specific <paramref name="client"/>.</summary> public static TokenValidationPolicyBuilder RequireSignatureWithKeyVault(this TokenValidationPolicyBuilder builder, KeyClient client, SignatureAlgorithm algorithm, long minimumRefreshInterval = CachedKeyProvider.DefaultMinimumRefreshInterval, long automaticRefreshInterval = CachedKeyProvider.DefaultAutomaticRefreshInterval) => builder.RequireSignature(client.VaultUri.ToString(), new KeyVaultKeyProvider(client, minimumRefreshInterval, automaticRefreshInterval), algorithm);
internal static void ThrowNotSupportedException_SignatureAlgorithm(SignatureAlgorithm algorithm, Jwk?key) => throw CreateNotSupportedException_SignatureAlgorithm(algorithm, key);
/// <summary> /// Adds a base64url encoded header to the cache. /// </summary> /// <param name="header"></param> /// <param name="alg"></param> /// <param name="base6UrlHeader"></param> public void AddHeader(JwtObject header, SignatureAlgorithm alg, ReadOnlySpan <byte> base6UrlHeader) { if (header.TryGetValue(HeaderParameters.KidUtf8, out var kidProperty) && kidProperty.Type == JwtTokenType.String && !(kidProperty.Value is null) && !(alg is null) && header.Count == 2) { var kid = (string)kidProperty.Value; bool lockTaken = false; try { _spinLock.Enter(ref lockTaken); var node = _head; while (node != null) { if (string.Equals(node.Kid, kid, StringComparison.Ordinal)) { break; } node = node.Next; } var key = alg.Id; if (node is null) { node = new Bucket(kid, new Dictionary <long, byte[]>(1) { { key, base6UrlHeader.ToArray() } }) { Next = _head }; } else { if (node.Entries.ContainsKey(key)) { node.Entries[key] = base6UrlHeader.ToArray(); } } if (_count >= MaxSize) { RemoveLeastRecentlyUsed(); } else { _count++; } if (_head != null) { _head.Previous = node; } _head = node; if (_tail is null) { _tail = node; } } finally { if (lockTaken) { _spinLock.Exit(); } } } }
internal static void ThrowNotSupportedException_Algorithm(SignatureAlgorithm algorithm) => throw CreateNotSupportedException_Algorithm(algorithm);
public TokenValidationPolicyBuilder RequireSignature(string jwksUrl, SignatureAlgorithm algorithm) => throw new NotSupportedException();
/// <inheritsdoc /> /// <inheritsdoc /> public override bool SupportSignature(SignatureAlgorithm algorithm) => throw new NotImplementedException();
/// <inheritdoc /> protected override SignatureVerifier CreateSignatureVerifier(SignatureAlgorithm algorithm) => throw ThrowHelper.CreateNotSupportedException_Algorithm(algorithm);
/// <summary> /// Initializes a new instance of the <see cref="AsymmetricJwk"/> class. /// </summary> protected AsymmetricJwk(SignatureAlgorithm alg) : base(alg) { }
/// <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); }