diff --git a/lib/fog/aws/kms.rb b/lib/fog/aws/kms.rb index 3b65dd230..8cc010641 100644 --- a/lib/fog/aws/kms.rb +++ b/lib/fog/aws/kms.rb @@ -22,6 +22,7 @@ class KMS < Fog::Service request :describe_key request :get_public_key request :schedule_key_deletion + request :sign model_path 'fog/aws/models/kms' model :key diff --git a/lib/fog/aws/parsers/kms/sign.rb b/lib/fog/aws/parsers/kms/sign.rb new file mode 100644 index 000000000..3a52e8b76 --- /dev/null +++ b/lib/fog/aws/parsers/kms/sign.rb @@ -0,0 +1,24 @@ +module Fog + module Parsers + module AWS + module KMS + class Sign < Fog::Parsers::Base + def reset + @response = {} + end + + def start_element(name, attrs = []) + super + end + + def end_element(name) + case name + when 'KeyId', 'Signature', 'SigningAlgorithm' + @response[name] = value + end + end + end + end + end + end +end diff --git a/lib/fog/aws/requests/kms/create_key.rb b/lib/fog/aws/requests/kms/create_key.rb index dac17d4fe..6912a6ec7 100644 --- a/lib/fog/aws/requests/kms/create_key.rb +++ b/lib/fog/aws/requests/kms/create_key.rb @@ -52,20 +52,18 @@ def create_key(*args) self.data[:keys][key_id] = key - size = key['KeySpec'].split('_').last - type = key['KeySpec'].split('_').first - case type - when 'ECC' - curve = { - 'ECC_NIST_P256' => 'secp256k1', - 'ECC_NIST_P384' => 'secp384r1', - 'ECC_NIST_P521' => 'secp521r1', - 'ECC_SECG_P256K1' => 'prime256v1' - }[key['KeySpec']] - self.data[:pkeys][key_id] = OpenSSL::PKey::EC.generate(curve) - when 'RSA' - self.data[:pkeys][key_id] = OpenSSL::PKey::RSA.generate(size.to_i) - end + klass, arg = { + 'ECC_NIST_P256' => [OpenSSL::PKey::EC, 'secp256k1'], + 'ECC_NIST_P384' => [OpenSSL::PKey::EC, 'secp384r1'], + 'ECC_NIST_P521' => [OpenSSL::PKey::EC, 'secp521r1'], + 'ECC_SECG_P256K1' => [OpenSSL::PKey::EC, 'prime256v1'], + 'RSA_2048' => [OpenSSL::PKey::RSA, 2048], + 'RSA_3072' => [OpenSSL::PKey::RSA, 3072], + 'RSA_4096' => [OpenSSL::PKey::RSA, 4096] + }[key['KeySpec']] + raise "Unknown or not-yet-implemented #{key['KeySpec']} KeySpec for kms create_key mocks" unless klass + + self.data[:pkeys][key_id] = klass.generate(arg) response.body = { 'KeyMetadata' => key } response diff --git a/lib/fog/aws/requests/kms/sign.rb b/lib/fog/aws/requests/kms/sign.rb new file mode 100644 index 000000000..0519046b2 --- /dev/null +++ b/lib/fog/aws/requests/kms/sign.rb @@ -0,0 +1,54 @@ +module Fog + module AWS + class KMS + class Real + require 'fog/aws/parsers/kms/sign' + + # Sign + # + # ==== Parameters + # + # === Returns + # + # ==== See Also + # https://docs.aws.amazon.com/kms/latest/APIReference/API_Sign.html + def sign(identifier, message, algorithm, options = {}) + request({ + 'Action' => 'Sign', + 'KeyId' => identifier, + 'Message' => message, + 'SigningAlgorithm' => algorithm, + :parser => Fog::Parsers::AWS::KMS::Sign.new + }.merge!(options)) + end + end + + class Mock + def sign(identifier, message, algorithm, _options = {}) + response = Excon::Response.new + pkey = self.data[:pkeys][identifier] + unless pkey + response.status = 404 + raise(Excon::Errors.status_error({ expects: 200 }, response)) + end + + # FIXME: SM2 support? + sha = "SHA#{algorithm.split('_SHA_').last}" + hash = OpenSSL::Digest.digest(sha, message) + + signopts = {} + signopts[:rsa_padding_mode] = 'pss' if algorithm.start_with?('RSASSA_PSS') + + signature = pkey.sign_raw(sha, hash, signopts) + + response.body = { + 'KeyId' => identifier, + 'Signature' => Base64.strict_encode64(signature), + 'SigningAlgorithm' => algorithm + } + response + end + end + end + end +end diff --git a/tests/requests/kms/helper.rb b/tests/requests/kms/helper.rb index 14a3abe56..5e27a6b41 100644 --- a/tests/requests/kms/helper.rb +++ b/tests/requests/kms/helper.rb @@ -42,6 +42,12 @@ module Formats 'KeyState' => String, 'PendingWindowInDays' => Integer }.freeze + + SIGN = { + 'KeyId' => String, + 'Signature' => String, + 'SigningAlgorithm' => String + }.freeze end end end diff --git a/tests/requests/kms/key_tests.rb b/tests/requests/kms/key_tests.rb index caba3c5a9..5fd71e4b3 100644 --- a/tests/requests/kms/key_tests.rb +++ b/tests/requests/kms/key_tests.rb @@ -29,6 +29,10 @@ Fog::AWS[:kms].list_keys.body end + tests('#sign').data_matches_schema(AWS::KMS::Formats::SIGN) do + Fog::AWS[:kms].sign(key_id, 'sign me', 'RSASSA_PSS_SHA_256').body + end + tests('#schedule_key_deletion').data_matches_schema(AWS::KMS::Formats::SCHEDULE_KEY_DELETION) do Fog::AWS[:kms].schedule_key_deletion(key_id, 7).body end