lib/jwt/jwk/hmac.rb in jwt-2.5.0 vs lib/jwt/jwk/hmac.rb in jwt-2.6.0
- old
+ new
@@ -2,65 +2,91 @@
module JWT
module JWK
class HMAC < KeyBase
KTY = 'oct'
- KTYS = [KTY, String].freeze
+ KTYS = [KTY, String, JWT::JWK::HMAC].freeze
+ HMAC_PUBLIC_KEY_ELEMENTS = %i[kty].freeze
+ HMAC_PRIVATE_KEY_ELEMENTS = %i[k].freeze
+ HMAC_KEY_ELEMENTS = (HMAC_PRIVATE_KEY_ELEMENTS + HMAC_PUBLIC_KEY_ELEMENTS).freeze
- attr_reader :signing_key
+ def initialize(key, params = nil, options = {})
+ params ||= {}
- def initialize(signing_key, options = {})
- raise ArgumentError, 'signing_key must be of type String' unless signing_key.is_a?(String)
+ # For backwards compatibility when kid was a String
+ params = { kid: params } if params.is_a?(String)
- @signing_key = signing_key
- super(options)
+ key_params = extract_key_params(key)
+
+ params = params.transform_keys(&:to_sym)
+ check_jwk(key_params, params)
+
+ super(options, key_params.merge(params))
end
+ def keypair
+ self[:k]
+ end
+
def private?
true
end
def public_key
nil
end
# See https://tools.ietf.org/html/rfc7517#appendix-A.3
def export(options = {})
- exported_hash = {
- kty: KTY,
- kid: kid
- }
-
- return exported_hash unless private? && options[:include_private] == true
-
- exported_hash.merge(
- k: signing_key
- )
+ exported = parameters.clone
+ exported.reject! { |k, _| HMAC_PRIVATE_KEY_ELEMENTS.include? k } unless private? && options[:include_private] == true
+ exported
end
def members
- {
- kty: KTY,
- k: signing_key
- }
+ HMAC_KEY_ELEMENTS.each_with_object({}) { |i, h| h[i] = self[i] }
end
- alias keypair signing_key # for backwards compatibility
+ alias signing_key keypair # for backwards compatibility
def key_digest
sequence = OpenSSL::ASN1::Sequence([OpenSSL::ASN1::UTF8String.new(signing_key),
OpenSSL::ASN1::UTF8String.new(KTY)])
OpenSSL::Digest::SHA256.hexdigest(sequence.to_der)
end
- class << self
- def import(jwk_data)
- jwk_k = jwk_data[:k] || jwk_data['k']
- jwk_kid = jwk_data[:kid] || jwk_data['kid']
+ def []=(key, value)
+ if HMAC_KEY_ELEMENTS.include?(key.to_sym)
+ raise ArgumentError, 'cannot overwrite cryptographic key attributes'
+ end
- raise JWT::JWKError, 'Key format is invalid for HMAC' unless jwk_k
+ super(key, value)
+ end
- new(jwk_k, kid: jwk_kid)
+ private
+
+ def extract_key_params(key)
+ case key
+ when JWT::JWK::HMAC
+ key.export(include_private: true)
+ when String # Accept String key as input
+ { kty: KTY, k: key }
+ when Hash
+ key.transform_keys(&:to_sym)
+ else
+ raise ArgumentError, 'key must be of type String or Hash with key parameters'
+ end
+ end
+
+ def check_jwk(keypair, params)
+ raise ArgumentError, 'cannot overwrite cryptographic key attributes' unless (HMAC_KEY_ELEMENTS & params.keys).empty?
+ raise JWT::JWKError, "Incorrect 'kty' value: #{keypair[:kty]}, expected #{KTY}" unless keypair[:kty] == KTY
+ raise JWT::JWKError, 'Key format is invalid for HMAC' unless keypair[:k]
+ end
+
+ class << self
+ def import(jwk_data)
+ new(jwk_data)
end
end
end
end
end