http_signatures 1.0.4 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 7d1755e9596abb9f3ad24afa289d497d069981da
4
- data.tar.gz: 4bb1f3a5312fc083a8b406848b84612f4c98bc7c
2
+ SHA256:
3
+ metadata.gz: '092ae9169cb08c0e6fdca80f3a28aeb61fd2a9abe82b325e64fe0045618eab88'
4
+ data.tar.gz: 5066113f840fdad906f6eb72f59c253857d726cb2589d50126058c5a817f65b7
5
5
  SHA512:
6
- metadata.gz: 115cdc1a07cd5382db15acd27d780d73dc8bd02c01ea5a42b6ab39eb5841513bb7eef4b7b05e0dd57716503892ed98bacdc82560b4bd36cd0702930bd13b2b24
7
- data.tar.gz: d9981768b583e5b92a97ff01f0cf94117be0b0fd8f2c02e7f7ad57761bebbece07df9cf0e6ef55ad9c3422da21b99db517b02b9f6d5368de8f762ee067331bb7
6
+ metadata.gz: a0c052a5d01aa9e34ba3b793e025e8c8a55c99112b82509b60ac8089ca140e5e28a94012bfef25b8ef7ed4d560c46dfd1ca3eea7453626e44a9b134f82a62946
7
+ data.tar.gz: bd443c9209eedb4f926f832e988a35c193e7a5a4573507fa844701f8b467a3c6c79e0d89470ff5b00389d6b0ed17a25fb830193b38101e660922056bb6ba2fd3
@@ -1,5 +1,6 @@
1
1
  require "http_signatures/algorithm"
2
2
  require "http_signatures/algorithm/hmac"
3
+ require "http_signatures/algorithm/rsa"
3
4
  require "http_signatures/context"
4
5
  require "http_signatures/header_list"
5
6
  require "http_signatures/key"
@@ -11,6 +12,9 @@ require "http_signatures/signer"
11
12
  require "http_signatures/signing_string"
12
13
  require "http_signatures/verification"
13
14
  require "http_signatures/verifier"
15
+ require "http_signatures/verification_algorithm"
16
+ require "http_signatures/verification_algorithm/hmac"
17
+ require "http_signatures/verification_algorithm/rsa"
14
18
  require "http_signatures/version"
15
19
 
16
20
  module HttpSignatures
@@ -5,6 +5,10 @@ module HttpSignatures
5
5
  case name
6
6
  when "hmac-sha1" then Hmac.new("sha1")
7
7
  when "hmac-sha256" then Hmac.new("sha256")
8
+ when "rsa-sha1" then Rsa.new("sha1")
9
+ when "rsa-sha256" then Rsa.new("sha256")
10
+ when "rsa-sha384" then Rsa.new("sha384")
11
+ when "rsa-sha512" then Rsa.new("sha512")
8
12
  else raise UnknownAlgorithm.new(name)
9
13
  end
10
14
  end
@@ -0,0 +1,33 @@
1
+ require "openssl"
2
+
3
+ module HttpSignatures
4
+ module Algorithm
5
+ class Rsa
6
+ def initialize(digest_name)
7
+ @digest_name = digest_name
8
+ end
9
+
10
+ def name
11
+ "rsa-#{@digest_name}"
12
+ end
13
+
14
+ def sign(key, data)
15
+ OpenSSL::PKey::RSA.new(private_key(key)).sign(@digest_name, data)
16
+ end
17
+
18
+ def verify(key, sign, data)
19
+ OpenSSL::PKey::RSA.new(public_key(key)).verify(@digest_name, sign, data)
20
+ end
21
+
22
+ private
23
+
24
+ def private_key(key)
25
+ key.fetch(:private_key)
26
+ end
27
+
28
+ def public_key(key)
29
+ key.fetch(:public_key)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -7,7 +7,14 @@ module HttpSignatures
7
7
  end
8
8
 
9
9
  def valid?
10
- signature_header_present? && signature_matches?
10
+ signature_header_present? && VerificationAlgorithm.create(algorithm).valid?(
11
+ message: @message,
12
+ key: key,
13
+ header_list: header_list,
14
+ provided_signature_base64: provided_signature_base64
15
+ )
16
+ rescue SignatureParametersParser::Error
17
+ false
11
18
  end
12
19
 
13
20
  private
@@ -16,25 +23,6 @@ module HttpSignatures
16
23
  @message.key?("Signature")
17
24
  end
18
25
 
19
- def signature_matches?
20
- expected_signature_base64 == provided_signature_base64
21
- rescue SignatureParametersParser::Error
22
- false
23
- end
24
-
25
- def expected_signature_base64
26
- Base64.strict_encode64(expected_signature_raw)
27
- end
28
-
29
- def expected_signature_raw
30
- Signature.new(
31
- message: @message,
32
- key: key,
33
- algorithm: algorithm,
34
- header_list: header_list,
35
- ).to_str
36
- end
37
-
38
26
  def provided_signature_base64
39
27
  parsed_parameters.fetch("signature")
40
28
  end
@@ -0,0 +1,17 @@
1
+ module HttpSignatures
2
+ class VerificationAlgorithm
3
+ def self.create(algorithm)
4
+ case algorithm
5
+ when HttpSignatures::Algorithm::Hmac then Hmac.new(algorithm)
6
+ when HttpSignatures::Algorithm::Rsa then Rsa.new(algorithm)
7
+ else raise UnknownAlgorithm.new(algorithm)
8
+ end
9
+ end
10
+
11
+ class UnknownAlgorithm < StandardError
12
+ def initialize(algorithm)
13
+ super("Unknown algorithm '#{algorithm}'")
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,26 @@
1
+ module HttpSignatures
2
+ class VerificationAlgorithm
3
+ class Hmac
4
+ def initialize(algorithm)
5
+ @algorithm = algorithm
6
+ end
7
+
8
+ def valid?(message:, key:, header_list:, provided_signature_base64:)
9
+ expected_signature_base64(message, key, header_list) == provided_signature_base64
10
+ end
11
+
12
+ def expected_signature_base64(message, key, header_list)
13
+ Base64.strict_encode64(expected_signature_raw(message, key, header_list))
14
+ end
15
+
16
+ def expected_signature_raw(message, key, header_list)
17
+ Signature.new(
18
+ message: message,
19
+ key: key,
20
+ algorithm: @algorithm,
21
+ header_list: header_list,
22
+ ).to_str
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,22 @@
1
+ require "base64"
2
+
3
+ module HttpSignatures
4
+ class VerificationAlgorithm
5
+ class Rsa
6
+ def initialize(algorithm)
7
+ @algorithm = algorithm
8
+ end
9
+
10
+ def valid?(message:, key:, header_list:, provided_signature_base64:)
11
+ @algorithm.verify(
12
+ key.secret,
13
+ Base64.strict_decode64(provided_signature_base64),
14
+ SigningString.new(
15
+ header_list: header_list,
16
+ message: message,
17
+ ).to_str
18
+ )
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,3 +1,3 @@
1
1
  module HttpSignatures
2
- VERSION = "1.0.4"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -0,0 +1,15 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIICXgIBAAKBgQDCFENGw33yGihy92pDjZQhl0C36rPJj+CvfSC8+q28hxA161QF
3
+ NUd13wuCTUcq0Qd2qsBe/2hFyc2DCJJg0h1L78+6Z4UMR7EOcpfdUE9Hf3m/hs+F
4
+ UR45uBJeDK1HSFHD8bHKD6kv8FPGfJTotc+2xjJwoYi+1hqp1fIekaxsyQIDAQAB
5
+ AoGBAJR8ZkCUvx5kzv+utdl7T5MnordT1TvoXXJGXK7ZZ+UuvMNUCdN2QPc4sBiA
6
+ QWvLw1cSKt5DsKZ8UETpYPy8pPYnnDEz2dDYiaew9+xEpubyeW2oH4Zx71wqBtOK
7
+ kqwrXa/pzdpiucRRjk6vE6YY7EBBs/g7uanVpGibOVAEsqH1AkEA7DkjVH28WDUg
8
+ f1nqvfn2Kj6CT7nIcE3jGJsZZ7zlZmBmHFDONMLUrXR/Zm3pR5m0tCmBqa5RK95u
9
+ 412jt1dPIwJBANJT3v8pnkth48bQo/fKel6uEYyboRtA5/uHuHkZ6FQF7OUkGogc
10
+ mSJluOdc5t6hI1VsLn0QZEjQZMEOWr+wKSMCQQCC4kXJEsHAve77oP6HtG/IiEn7
11
+ kpyUXRNvFsDE0czpJJBvL/aRFUJxuRK91jhjC68sA7NsKMGg5OXb5I5Jj36xAkEA
12
+ gIT7aFOYBFwGgQAQkWNKLvySgKbAZRTeLBacpHMuQdl1DfdntvAyqpAZ0lY0RKmW
13
+ G6aFKaqQfOXKCyWoUiVknQJAXrlgySFci/2ueKlIE1QqIiLSZ8V8OlpFLRnb1pzI
14
+ 7U1yQXnTAEFYM560yJlzUpOb1V4cScGd365tiSMvxLOvTA==
15
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,6 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCFENGw33yGihy92pDjZQhl0C3
3
+ 6rPJj+CvfSC8+q28hxA161QFNUd13wuCTUcq0Qd2qsBe/2hFyc2DCJJg0h1L78+6
4
+ Z4UMR7EOcpfdUE9Hf3m/hs+FUR45uBJeDK1HSFHD8bHKD6kv8FPGfJTotc+2xjJw
5
+ oYi+1hqp1fIekaxsyQIDAQAB
6
+ -----END PUBLIC KEY-----
@@ -0,0 +1,144 @@
1
+ # NOTE: All test data in this spec are same as
2
+ # https://github.com/tomitribe/http-signatures-java/blob/master/src/test/java/org/tomitribe/auth/signatures/RsaTest.java
3
+
4
+ RSpec.shared_examples_for "signer" do |expected_signature|
5
+ let(:provided_signature) { HttpSignatures::SignatureParametersParser.new(message["signature"]).parse.fetch("signature") }
6
+ it "returns expected signature" do
7
+ context.signer.sign message
8
+ expect(provided_signature).to eq(expected_signature)
9
+ end
10
+ end
11
+
12
+ RSpec.shared_examples_for "verifier" do
13
+ it "validates signature" do
14
+ context.signer.sign message
15
+ expect(context.verifier.valid? message).to eq(true)
16
+ end
17
+
18
+ it "rejects if a signed header has changed" do
19
+ context.signer.sign message
20
+ message["Date"] = "Thu, 12 Jan 2012 21:31:40 GMT"
21
+ expect(context.verifier.valid? message).to eq(false)
22
+ end
23
+ end
24
+
25
+ RSpec.describe "Using RSA" do
26
+ let(:public_key) { File.read(File.join(__dir__, "keys", "id_rsa.pub")) }
27
+ let(:private_key) { File.read(File.join(__dir__, "keys", "id_rsa")) }
28
+
29
+ let(:message) do
30
+ Net::HTTP::Post.new(
31
+ "/foo?param=value&pet=dog",
32
+ "Host" => "example.org",
33
+ "Date" => "Thu, 05 Jan 2012 21:31:40 GMT",
34
+ "Content-Type" => "application/json",
35
+ "Digest" => "SHA-256=X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=",
36
+ "Accept" => "*/*",
37
+ "Content-Length" => "18"
38
+ )
39
+ end
40
+
41
+ let(:context) do
42
+ HttpSignatures::Context.new(
43
+ keys: {
44
+ "my_rsa_key_pair" => {
45
+ private_key: private_key,
46
+ public_key: public_key,
47
+ },
48
+ },
49
+ signing_key_id: "my_rsa_key_pair",
50
+ algorithm: algorithm,
51
+ headers: headers,
52
+ )
53
+ end
54
+
55
+ describe "context.signer.sign and context.verifier.valid?" do
56
+ context "algorithm is rsa-sha1" do
57
+ let(:algorithm) { "rsa-sha1" }
58
+
59
+ context "headers are %w{date}" do
60
+ let(:headers) { %w{date} }
61
+ it_behaves_like "signer", "kcX/cWMRQEjUPfF6AO7ANZ/eQkpRd" +
62
+ "/4+dr3g1B5HZBn3vRDxGFbDRY19HeJUUlBAgmvolRwLlrVkz" +
63
+ "LOmYdug6Ff01UUl6gX+TksGbsxagbNUNoEx0hrX3+8Jbd+x8" +
64
+ "gx9gZxA7DwXww1u3bGrmChnfkdOofY52KhUllUox4mmBeI="
65
+ it_behaves_like "verifier"
66
+ end
67
+
68
+ context "headers are %w{(request-target) host date}" do
69
+ let(:headers) { %w{(request-target) host date} }
70
+ it_behaves_like "signer", "F6g4qdBSHBcWo1iMsHetQU9TnPF39" +
71
+ "naVHQogAhgvY6wh0/cdkquN4D6CInTyEHtMuv7xlOt0yBaVt" +
72
+ "brrNP5JZKquYMW2JC3FXdtIiaYWhLUb/Nmb+JPr6C8AnxMzc" +
73
+ "fNfuOZFn3X7ekA32qbfnYr7loHqpEGUr+G1NYsckEXdlM4="
74
+ it_behaves_like "verifier"
75
+ end
76
+ end
77
+
78
+ context "algorithm is sha256" do
79
+ let(:algorithm) { "rsa-sha256" }
80
+
81
+ context "headers are %w{date}" do
82
+ let(:headers) { %w{date} }
83
+ it_behaves_like "signer", "ATp0r26dbMIxOopqw0OfABDT7CKMI" +
84
+ "oENumuruOtarj8n/97Q3htHFYpH8yOSQk3Z5zh8UxUym6FYT" +
85
+ "b5+A0Nz3NRsXJibnYi7brE/4tx5But9kkFGzG+xpUmimN4c3" +
86
+ "TMN7OFH//+r8hBf7BT9/GmHDUVZT2JzWGLZES2xDOUuMtA="
87
+ it_behaves_like "verifier"
88
+ end
89
+
90
+ context "headers are %w{(request-target) host date}" do
91
+ let(:headers) { %w{(request-target) host date} }
92
+ it_behaves_like "signer", "DT9vcDFbit2ahGZowjUzzih+sVpKM" +
93
+ "IPZrXy1DMljImYNSJ3UEweTMfF3MUFjdNwYH59IDJoB+QTg3" +
94
+ "Rpm5xLvMWD7tql/Ng/NCJs8gYSNjOQidArEpWp88c5IQPDXn" +
95
+ "1lnJMU6dNXZNxc8Yqj+mIYhwHpKEKTqnvEtnCvB/6y/dIM="
96
+ it_behaves_like "verifier"
97
+ end
98
+ end
99
+
100
+ context "algorithm is sha384" do
101
+ let(:algorithm) { "rsa-sha384" }
102
+
103
+ context "headers are %w{date}" do
104
+ let(:headers) { %w{date} }
105
+ it_behaves_like "signer", "AYtR6NQy+59Ta3X1GYNlfOzJo4Sg+" +
106
+ "aB+ulDkR6Q2/8egvByRx5l0+t/2abAaFHf33SDojHYWPlpuj" +
107
+ "HM26ExZPFXeYzG9sRctKD7XKrA/F6LRXEm1RXLFvfvLXQw4P" +
108
+ "4HE1PMH+gCw2E+6IoTnbcimQtZ82SkF1uDRtLDhR6iqpFI="
109
+ it_behaves_like "verifier"
110
+ end
111
+
112
+ context "headers are %w{(request-target) host date}" do
113
+ let(:headers) { %w{(request-target) host date} }
114
+ it_behaves_like "signer", "mRaP0Z5lh9XKGDahdsomoKR9Kjsj9" +
115
+ "a/lgUEpZDQpvSZq5NhODEjmQh1qRn6Sx/c+AFl67yzDYAMXx" +
116
+ "9h49ZOpKpuj4FGrz5/DIK7cdn9wXBKqDYgDfwOF9O5jNOE1r" +
117
+ "9zbORTH0XxA8WE9H/MXoOrDIH1NjM5o9I4ErT4zKnD5OsQ="
118
+ it_behaves_like "verifier"
119
+ end
120
+ end
121
+
122
+ context "algorithm is sha512" do
123
+ let(:algorithm) { "rsa-sha512" }
124
+
125
+ context "headers are %w{date}" do
126
+ let(:headers) { %w{date} }
127
+ it_behaves_like "signer", "IItboA8OJgL8WSAnJa8MND04s9j7d" +
128
+ "B6IJIBVpOGJph8Tmkc5yUAYjvO/UQUKytRBe5CSv2GLfTAmE" +
129
+ "7SuRgGGMwdQZubNJqRCiVPKBpuA47lXrKgC/wB0QAMkPHI6c" +
130
+ "PllBZRixmjZuU9mIbuLjXMHR+v/DZwOHT9k8x0ILUq2rKE="
131
+ it_behaves_like "verifier"
132
+ end
133
+
134
+ context "headers are %w{(request-target) host date}" do
135
+ let(:headers) { %w{(request-target) host date} }
136
+ it_behaves_like "signer", "ggIa4bcI7q377gNoQ7qVYxTA4pEOl" +
137
+ "xlFzRtiQV0SdPam4sK58SFO9EtzE0P1zVTymTnsSRChmFU2p" +
138
+ "n+R9VzkAhQ+yEbTqzu+mgHc4P1L5IeeXQ5aAmGENfkRbm2vd" +
139
+ "OZzP5j6ruB+SJXIlhnaum2lsuyytSS0m/GkWvFJVZFu33M="
140
+ it_behaves_like "verifier"
141
+ end
142
+ end
143
+ end
144
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: http_signatures
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Annesley
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-17 00:00:00.000000000 Z
11
+ date: 2019-07-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -70,6 +70,7 @@ files:
70
70
  - lib/http_signatures.rb
71
71
  - lib/http_signatures/algorithm.rb
72
72
  - lib/http_signatures/algorithm/hmac.rb
73
+ - lib/http_signatures/algorithm/rsa.rb
73
74
  - lib/http_signatures/context.rb
74
75
  - lib/http_signatures/header_list.rb
75
76
  - lib/http_signatures/key.rb
@@ -80,12 +81,18 @@ files:
80
81
  - lib/http_signatures/signer.rb
81
82
  - lib/http_signatures/signing_string.rb
82
83
  - lib/http_signatures/verification.rb
84
+ - lib/http_signatures/verification_algorithm.rb
85
+ - lib/http_signatures/verification_algorithm/hmac.rb
86
+ - lib/http_signatures/verification_algorithm/rsa.rb
83
87
  - lib/http_signatures/verifier.rb
84
88
  - lib/http_signatures/version.rb
85
89
  - spec/algorithm_spec.rb
86
90
  - spec/context_spec.rb
87
91
  - spec/header_list_spec.rb
88
92
  - spec/key_store_spec.rb
93
+ - spec/keys/id_rsa
94
+ - spec/keys/id_rsa.pub
95
+ - spec/rsa_spec.rb
89
96
  - spec/signature_parameters_parser_spec.rb
90
97
  - spec/signature_parameters_spec.rb
91
98
  - spec/signer_spec.rb
@@ -111,8 +118,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
118
  - !ruby/object:Gem::Version
112
119
  version: '0'
113
120
  requirements: []
114
- rubyforge_project:
115
- rubygems_version: 2.2.2
121
+ rubygems_version: 3.0.3
116
122
  signing_key:
117
123
  specification_version: 4
118
124
  summary: Sign and verify HTTP messages
@@ -121,10 +127,12 @@ test_files:
121
127
  - spec/context_spec.rb
122
128
  - spec/header_list_spec.rb
123
129
  - spec/key_store_spec.rb
130
+ - spec/keys/id_rsa
131
+ - spec/keys/id_rsa.pub
132
+ - spec/rsa_spec.rb
124
133
  - spec/signature_parameters_parser_spec.rb
125
134
  - spec/signature_parameters_spec.rb
126
135
  - spec/signer_spec.rb
127
136
  - spec/signing_string_spec.rb
128
137
  - spec/spec_helper.rb
129
138
  - spec/verifier_spec.rb
130
- has_rdoc: