http_signatures 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: