jose 0.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.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +20 -0
  3. data/.gitignore +9 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +4 -0
  7. data/CODE_OF_CONDUCT.md +13 -0
  8. data/Gemfile +20 -0
  9. data/LICENSE.txt +373 -0
  10. data/README.md +41 -0
  11. data/Rakefile +10 -0
  12. data/bin/console +14 -0
  13. data/bin/setup +7 -0
  14. data/jose.gemspec +36 -0
  15. data/lib/jose.rb +61 -0
  16. data/lib/jose/jwa.rb +21 -0
  17. data/lib/jose/jwa/aes_kw.rb +105 -0
  18. data/lib/jose/jwa/concat_kdf.rb +50 -0
  19. data/lib/jose/jwa/pkcs1.rb +269 -0
  20. data/lib/jose/jwa/pkcs7.rb +23 -0
  21. data/lib/jose/jwe.rb +290 -0
  22. data/lib/jose/jwe/alg.rb +12 -0
  23. data/lib/jose/jwe/alg_aes_gcm_kw.rb +98 -0
  24. data/lib/jose/jwe/alg_aes_kw.rb +57 -0
  25. data/lib/jose/jwe/alg_dir.rb +40 -0
  26. data/lib/jose/jwe/alg_ecdh_es.rb +123 -0
  27. data/lib/jose/jwe/alg_pbes2.rb +90 -0
  28. data/lib/jose/jwe/alg_rsa.rb +63 -0
  29. data/lib/jose/jwe/enc.rb +8 -0
  30. data/lib/jose/jwe/enc_aes_cbc_hmac.rb +80 -0
  31. data/lib/jose/jwe/enc_aes_gcm.rb +68 -0
  32. data/lib/jose/jwe/zip.rb +7 -0
  33. data/lib/jose/jwe/zip_def.rb +28 -0
  34. data/lib/jose/jwk.rb +347 -0
  35. data/lib/jose/jwk/kty.rb +34 -0
  36. data/lib/jose/jwk/kty_ec.rb +179 -0
  37. data/lib/jose/jwk/kty_oct.rb +104 -0
  38. data/lib/jose/jwk/kty_rsa.rb +185 -0
  39. data/lib/jose/jwk/pem.rb +19 -0
  40. data/lib/jose/jwk/set.rb +2 -0
  41. data/lib/jose/jws.rb +242 -0
  42. data/lib/jose/jws/alg.rb +10 -0
  43. data/lib/jose/jws/alg_ecdsa.rb +41 -0
  44. data/lib/jose/jws/alg_hmac.rb +41 -0
  45. data/lib/jose/jws/alg_rsa_pkcs1_v1_5.rb +41 -0
  46. data/lib/jose/jws/alg_rsa_pss.rb +41 -0
  47. data/lib/jose/jwt.rb +145 -0
  48. data/lib/jose/version.rb +3 -0
  49. metadata +162 -0
@@ -0,0 +1,104 @@
1
+ class JOSE::JWK::KTY_oct < Struct.new(:oct)
2
+
3
+ # JOSE::JWK callbacks
4
+
5
+ def self.from_map(fields)
6
+ if fields['kty'] == 'oct' and fields['k'].is_a?(String)
7
+ return JOSE::JWK::KTY_oct.new(JOSE.urlsafe_decode64(fields['k'])), fields.except('kty', 'k')
8
+ else
9
+ raise ArgumentError, "invalid 'oct' JWK"
10
+ end
11
+ end
12
+
13
+ def to_key
14
+ return oct
15
+ end
16
+
17
+ def to_map(fields)
18
+ return fields.put('k', JOSE.urlsafe_encode64(oct)).put('kty', 'oct')
19
+ end
20
+
21
+ def to_public_map(fields)
22
+ return to_map(fields)
23
+ end
24
+
25
+ def to_thumbprint_map(fields)
26
+ return to_public_map(fields).slice('k', 'kty')
27
+ end
28
+
29
+ # JOSE::JWK::KTY callbacks
30
+
31
+ def block_encryptor(fields, plain_text)
32
+ enc = case (oct.bytesize * 8)
33
+ when 128
34
+ 'A128GCM'
35
+ when 192
36
+ 'A192GCM'
37
+ when 256
38
+ 'A256GCM'
39
+ when 384
40
+ 'A192CBC-HS384'
41
+ when 512
42
+ 'A256CBC-HS512'
43
+ else
44
+ raise ArgumentError, "oct of size #{oct.bytesize * 8} has no default block encryptor"
45
+ end
46
+ return JOSE::Map[
47
+ 'alg' => 'dir',
48
+ 'enc' => enc
49
+ ]
50
+ end
51
+
52
+ def derive_key
53
+ return oct
54
+ end
55
+
56
+ def self.generate_key(size)
57
+ if size.is_a?(Array) and size.length == 2 and size[0] == :oct
58
+ size = size[1]
59
+ end
60
+ case size
61
+ when Integer
62
+ return from_oct(SecureRandom.random_bytes(size))
63
+ else
64
+ raise ArgumentError, "'size' must be an Integer"
65
+ end
66
+ end
67
+
68
+ def generate_key(fields)
69
+ kty, other_fields = JOSE::JWK::KTY_oct.generate_key(oct.bytesize)
70
+ return kty, fields.delete('kid').merge(other_fields)
71
+ end
72
+
73
+ def key_encryptor(fields, key)
74
+ return JOSE::JWK::KTY.key_encryptor(self, fields, key)
75
+ end
76
+
77
+ def sign(message, digest_type)
78
+ return OpenSSL::HMAC.digest(digest_type.new, oct, message)
79
+ end
80
+
81
+ def signer(fields = nil, plain_text = nil)
82
+ return JOSE::Map['alg' => 'HS256']
83
+ end
84
+
85
+ def verify(message, digest_type, signature)
86
+ return JOSE::JWA.constant_time_compare(signature, sign(message, digest_type))
87
+ end
88
+
89
+ # API functions
90
+
91
+ def self.from_oct(binary)
92
+ case binary
93
+ when String
94
+ return JOSE::JWK::KTY_oct.new(binary), JOSE::Map[]
95
+ else
96
+ raise ArgumentError, "'binary' must be a String"
97
+ end
98
+ end
99
+
100
+ def to_oct
101
+ return oct
102
+ end
103
+
104
+ end
@@ -0,0 +1,185 @@
1
+ class JOSE::JWK::KTY_RSA < Struct.new(:key)
2
+
3
+ # JOSE::JWK callbacks
4
+
5
+ def self.from_map(fields)
6
+ if fields['kty'] == 'RSA' and fields['e'].is_a?(String) and fields['n'].is_a?(String)
7
+ if fields['oth'].is_a?(Array)
8
+ raise ArgumentError, "multi-prime RSA keys are not supported"
9
+ elsif fields['d'].is_a?(String)
10
+ if fields['dp'].is_a?(String) and fields['dq'].is_a?(String) and fields['p'].is_a?(String) and fields['q'].is_a?(String) and fields['qi'].is_a?(String)
11
+ rsa = OpenSSL::PKey::RSA.new
12
+ rsa.d = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['d']), 2)
13
+ rsa.dmp1 = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['dp']), 2)
14
+ rsa.dmq1 = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['dq']), 2)
15
+ rsa.e = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['e']), 2)
16
+ rsa.n = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['n']), 2)
17
+ rsa.p = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['p']), 2)
18
+ rsa.q = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['q']), 2)
19
+ rsa.iqmp = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['qi']), 2)
20
+ return JOSE::JWK::KTY_RSA.new(rsa), fields.except('kty', 'd', 'dp', 'dq', 'e', 'n', 'p', 'q', 'qi')
21
+ else
22
+ raise ArgumentError, "invalid 'RSA' JWK"
23
+ end
24
+ else
25
+ rsa = OpenSSL::PKey::RSA.new
26
+ rsa.e = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['e']), 2)
27
+ rsa.n = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['n']), 2)
28
+ return JOSE::JWK::KTY_RSA.new(rsa), fields.except('kty', 'e', 'n')
29
+ end
30
+ else
31
+ raise ArgumentError, "invalid 'RSA' JWK"
32
+ end
33
+ end
34
+
35
+ def to_key
36
+ return key
37
+ end
38
+
39
+ def to_map(fields)
40
+ if key.private?
41
+ return fields.
42
+ put('d', JOSE.urlsafe_encode64(key.d.to_s(2))).
43
+ put('dp', JOSE.urlsafe_encode64(key.dmp1.to_s(2))).
44
+ put('dq', JOSE.urlsafe_encode64(key.dmq1.to_s(2))).
45
+ put('e', JOSE.urlsafe_encode64(key.e.to_s(2))).
46
+ put('kty', 'RSA').
47
+ put('n', JOSE.urlsafe_encode64(key.n.to_s(2))).
48
+ put('p', JOSE.urlsafe_encode64(key.p.to_s(2))).
49
+ put('q', JOSE.urlsafe_encode64(key.q.to_s(2))).
50
+ put('qi', JOSE.urlsafe_encode64(key.iqmp.to_s(2))).
51
+ put('q', JOSE.urlsafe_encode64(key.q.to_s(2)))
52
+ else
53
+ return fields.
54
+ put('e', JOSE.urlsafe_encode64(key.e.to_s(2))).
55
+ put('kty', 'RSA').
56
+ put('n', JOSE.urlsafe_encode64(key.n.to_s(2)))
57
+ end
58
+ end
59
+
60
+ def to_public_map(fields)
61
+ return to_map(fields).except('d', 'dp', 'dq', 'p', 'q', 'qi', 'oth')
62
+ end
63
+
64
+ def to_thumbprint_map(fields)
65
+ return to_public_map(fields).slice('e', 'kty', 'n')
66
+ end
67
+
68
+ # JOSE::JWK::KTY callbacks
69
+
70
+ def block_encryptor(fields, plain_text)
71
+ return JOSE::Map[
72
+ 'alg' => 'RSA-OAEP',
73
+ 'enc' => 'A128GCM'
74
+ ]
75
+ end
76
+
77
+ def decrypt_private(cipher_text, rsa_padding: :rsa_pkcs1_padding, rsa_oaep_md: nil)
78
+ case rsa_padding
79
+ when :rsa_pkcs1_padding
80
+ return key.private_decrypt(cipher_text, OpenSSL::PKey::RSA::PKCS1_PADDING)
81
+ when :rsa_pkcs1_oaep_padding
82
+ rsa_oaep_md ||= OpenSSL::Digest::SHA1
83
+ if rsa_oaep_md == OpenSSL::Digest::SHA1
84
+ return key.private_decrypt(cipher_text, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
85
+ elsif rsa_oaep_md == OpenSSL::Digest::SHA256
86
+ return JOSE::JWA::PKCS1.rsaes_oaep_decrypt(rsa_oaep_md, cipher_text, key)
87
+ else
88
+ raise ArgumentError, "unsupported RSA OAEP md: #{rsa_oaep_md.inspect}"
89
+ end
90
+ else
91
+ raise ArgumentError, "unsupported RSA padding: #{rsa_padding.inspect}"
92
+ end
93
+ end
94
+
95
+ def encrypt_public(plain_text, rsa_padding: :rsa_pkcs1_padding, rsa_oaep_md: nil)
96
+ case rsa_padding
97
+ when :rsa_pkcs1_padding
98
+ return key.public_encrypt(plain_text, OpenSSL::PKey::RSA::PKCS1_PADDING)
99
+ when :rsa_pkcs1_oaep_padding
100
+ rsa_oaep_md ||= OpenSSL::Digest::SHA1
101
+ if rsa_oaep_md == OpenSSL::Digest::SHA1
102
+ return key.public_encrypt(plain_text, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
103
+ elsif rsa_oaep_md == OpenSSL::Digest::SHA256
104
+ return JOSE::JWA::PKCS1.rsaes_oaep_encrypt(rsa_oaep_md, plain_text, key)
105
+ else
106
+ raise ArgumentError, "unsupported RSA OAEP md: #{rsa_oaep_md.inspect}"
107
+ end
108
+ else
109
+ raise ArgumentError, "unsupported RSA padding: #{rsa_padding.inspect}"
110
+ end
111
+ end
112
+
113
+ def self.generate_key(modulus_size, exponent_size = nil)
114
+ if modulus_size.is_a?(Array)
115
+ if modulus_size.length == 2 and modulus_size[0] == :rsa
116
+ modulus_size = modulus_size[1]
117
+ elsif modulus_size.length == 3 and modulus_size[0] == :rsa
118
+ exponent_size = modulus_size[2]
119
+ modulus_size = modulus_size[1]
120
+ end
121
+ end
122
+ if modulus_size.is_a?(Integer) and (exponent_size.nil? or exponent_size.is_a?(Integer))
123
+ return from_key(OpenSSL::PKey::RSA.generate(modulus_size, exponent_size))
124
+ else
125
+ raise ArgumentError, "'modulus_size' must be an Integer and 'exponent_size' must be nil or an Integer"
126
+ end
127
+ end
128
+
129
+ def generate_key(fields)
130
+ kty, other_fields = JOSE::JWK::KTY_RSA.generate_key([:rsa, key.n.num_bits, key.e.to_i])
131
+ return kty, fields.delete('kid').merge(other_fields)
132
+ end
133
+
134
+ def key_encryptor(fields, key)
135
+ return JOSE::JWK::KTY.key_encryptor(self, fields, key)
136
+ end
137
+
138
+ def sign(message, digest_type, padding: :rsa_pkcs1_padding)
139
+ case padding
140
+ when :rsa_pkcs1_padding
141
+ return key.sign(digest_type.new, message)
142
+ when :rsa_pkcs1_pss_padding
143
+ return JOSE::JWA::PKCS1.rsassa_pss_sign(digest_type, message, key)
144
+ else
145
+ raise ArgumentError, "unsupported RSA padding: #{padding.inspect}"
146
+ end
147
+ end
148
+
149
+ def signer(fields = nil, plain_text = nil)
150
+ if key.private?
151
+ return JOSE::Map['alg' => 'RS256']
152
+ else
153
+ raise ArgumentError, "signing not supported for public keys"
154
+ end
155
+ end
156
+
157
+ def verify(message, digest_type, signature, padding: :rsa_pkcs1_padding)
158
+ case padding
159
+ when :rsa_pkcs1_padding
160
+ return key.verify(digest_type.new, signature, message)
161
+ when :rsa_pkcs1_pss_padding
162
+ return JOSE::JWA::PKCS1.rsassa_pss_verify(digest_type, message, signature, key)
163
+ else
164
+ raise ArgumentError, "unsupported RSA padding: #{padding.inspect}"
165
+ end
166
+ rescue OpenSSL::PKey::PKeyError # jruby raises this error if the signature is invalid
167
+ false
168
+ end
169
+
170
+ # API functions
171
+
172
+ def self.from_key(key)
173
+ case key
174
+ when OpenSSL::PKey::RSA
175
+ return JOSE::JWK::KTY_RSA.new(key), JOSE::Map[]
176
+ else
177
+ raise ArgumentError, "'key' must be a OpenSSL::PKey::RSA"
178
+ end
179
+ end
180
+
181
+ def to_pem(password = nil)
182
+ return JOSE::JWK::PEM.to_binary(key, password)
183
+ end
184
+
185
+ end
@@ -0,0 +1,19 @@
1
+ module JOSE::JWK::PEM
2
+
3
+ extend self
4
+
5
+ def from_binary(object, password = nil)
6
+ pkey = OpenSSL::PKey.read(object, password)
7
+ return JOSE::JWK::KTY.from_key(pkey)
8
+ end
9
+
10
+ def to_binary(key, password = nil)
11
+ if password
12
+ cipher = OpenSSL::Cipher.new('DES-EDE3-CBC')
13
+ return key.to_pem(cipher, password)
14
+ else
15
+ return key.to_pem
16
+ end
17
+ end
18
+
19
+ end
@@ -0,0 +1,2 @@
1
+ class JOSE::JWK::Set
2
+ end
data/lib/jose/jws.rb ADDED
@@ -0,0 +1,242 @@
1
+ module JOSE
2
+
3
+ class SignedBinary < ::String
4
+ def expand
5
+ return JOSE::JWS.expand(self)
6
+ end
7
+ end
8
+
9
+ class SignedMap < JOSE::Map
10
+ def compact
11
+ return JOSE::JWS.compact(self)
12
+ end
13
+ end
14
+
15
+ class JWS < Struct.new(:alg, :b64, :fields)
16
+
17
+ # Decode API
18
+
19
+ def self.from(object, modules = {})
20
+ case object
21
+ when JOSE::Map, Hash
22
+ return from_map(object, modules)
23
+ when String
24
+ return from_binary(object, modules)
25
+ when JOSE::JWS
26
+ return object
27
+ else
28
+ raise ArgumentError, "'object' must be a Hash, String, or JOSE::JWS"
29
+ end
30
+ end
31
+
32
+ def self.from_binary(object, modules = {})
33
+ case object
34
+ when String
35
+ return from_map(JOSE.decode(object), modules)
36
+ else
37
+ raise ArgumentError, "'object' must be a String"
38
+ end
39
+ end
40
+
41
+ def self.from_file(file, modules = {})
42
+ return from_binary(File.binread(file), modules)
43
+ end
44
+
45
+ def self.from_map(object, modules = {})
46
+ case object
47
+ when JOSE::Map, Hash
48
+ return from_fields(JOSE::JWS.new(nil, nil, JOSE::Map.new(object)), modules)
49
+ else
50
+ raise ArgumentError, "'object' must be a Hash"
51
+ end
52
+ end
53
+
54
+ # Encode API
55
+
56
+ def self.to_binary(jws)
57
+ return from(jws).to_binary
58
+ end
59
+
60
+ def to_binary
61
+ return JOSE.encode(to_map)
62
+ end
63
+
64
+ def self.to_file(jws, file)
65
+ return from(jws).to_file(file)
66
+ end
67
+
68
+ def to_file(file)
69
+ return File.binwrite(file, to_binary)
70
+ end
71
+
72
+ def self.to_map(jws)
73
+ return from(jws).to_map
74
+ end
75
+
76
+ def to_map
77
+ return alg.to_map(fields)
78
+ end
79
+
80
+ # API
81
+
82
+ def self.compact(map)
83
+ if map.is_a?(Hash) or map.is_a?(JOSE::Map)
84
+ return JOSE::SignedBinary.new([
85
+ map['protected'] || '',
86
+ '.',
87
+ map['payload'] || '',
88
+ '.',
89
+ map['signature'] || ''
90
+ ].join)
91
+ else
92
+ raise ArgumentError, "'map' must be a Hash or a JOSE::Map"
93
+ end
94
+ end
95
+
96
+ def self.expand(binary)
97
+ if binary.is_a?(String)
98
+ parts = binary.split('.')
99
+ if parts.length == 3
100
+ protected_binary, payload, signature = parts
101
+ return JOSE::SignedMap[
102
+ 'payload' => payload,
103
+ 'protected' => protected_binary,
104
+ 'signature' => signature
105
+ ]
106
+ else
107
+ raise ArgumentError, "'binary' is not a valid signed String"
108
+ end
109
+ else
110
+ raise ArgumentError, "'binary' must be a String"
111
+ end
112
+ end
113
+
114
+ def self.peek_payload(signed)
115
+ if signed.is_a?(String)
116
+ signed = expand(signed)
117
+ end
118
+ return JOSE.urlsafe_decode64(signed['payload'])
119
+ end
120
+
121
+ def self.peek_protected(signed)
122
+ if signed.is_a?(String)
123
+ signed = expand(signed)
124
+ end
125
+ return JOSE::Map.new(JOSE.decode(JOSE.urlsafe_decode64(signed['protected'])))
126
+ end
127
+
128
+ def self.sign(key, plain_text, jws, header = nil)
129
+ return from(jws).sign(key, plain_text, header)
130
+ end
131
+
132
+ def sign(key, plain_text, header = nil)
133
+ protected_binary = JOSE.urlsafe_encode64(to_binary)
134
+ payload = JOSE.urlsafe_encode64(plain_text)
135
+ signing_input = signing_input(plain_text, protected_binary)
136
+ signature = JOSE.urlsafe_encode64(alg.sign(key, signing_input))
137
+ return signature_to_map(payload, protected_binary, header, key, signature)
138
+ end
139
+
140
+ # See https://tools.ietf.org/html/draft-ietf-jose-jws-signing-input-options-04
141
+ def signing_input(payload, protected_binary = JOSE.urlsafe_encode64(to_binary))
142
+ if b64 == true or b64.nil?
143
+ payload = JOSE.urlsafe_encode64(payload)
144
+ end
145
+ return [protected_binary, '.', payload].join
146
+ end
147
+
148
+ def self.verify(key, signed)
149
+ if signed.is_a?(String)
150
+ signed = JOSE::JWS.expand(signed)
151
+ end
152
+ if signed.is_a?(Hash)
153
+ signed = JOSE::SignedMap.new(signed)
154
+ end
155
+ if signed.is_a?(JOSE::Map) and signed['payload'].is_a?(String) and signed['protected'].is_a?(String) and signed['signature'].is_a?(String)
156
+ jws = from_binary(JOSE.urlsafe_decode64(signed['protected']))
157
+ signature = JOSE.urlsafe_decode64(signed['signature'])
158
+ plain_text = JOSE.urlsafe_decode64(signed['payload'])
159
+ return jws.verify(key, plain_text, signature, signed['protected'])
160
+ else
161
+ raise ArgumentError, "'signed' is not a valid signed String, Hash, or JOSE::Map"
162
+ end
163
+ end
164
+
165
+ def verify(key, plain_text, signature, protected_binary = JOSE.urlsafe_encode64(to_binary))
166
+ payload = JOSE.urlsafe_encode64(plain_text)
167
+ signing_input = signing_input(plain_text, protected_binary)
168
+ return alg.verify(key, signing_input, signature), plain_text, self
169
+ end
170
+
171
+ def self.verify_strict(key, allow, signed)
172
+ if signed.is_a?(String)
173
+ signed = JOSE::JWS.expand(signed)
174
+ end
175
+ if signed.is_a?(Hash)
176
+ signed = JOSE::SignedMap.new(signed)
177
+ end
178
+ if signed.is_a?(JOSE::Map) and signed['payload'].is_a?(String) and signed['protected'].is_a?(String) and signed['signature'].is_a?(String)
179
+ protected_map = JOSE.decode(JOSE.urlsafe_decode64(signed['protected']))
180
+ plain_text = JOSE.urlsafe_decode64(signed['payload'])
181
+ if allow.member?(protected_map['alg'])
182
+ jws = from_map(protected_map)
183
+ signature = JOSE.urlsafe_decode64(signed['signature'])
184
+ return jws.verify(key, plain_text, signature, signed['protected'])
185
+ else
186
+ return false, plain_text, protected_map
187
+ end
188
+ else
189
+ raise ArgumentError, "'signed' is not a valid signed String, Hash, or JOSE::Map"
190
+ end
191
+ end
192
+
193
+ private
194
+
195
+ def self.from_fields(jws, modules)
196
+ if jws.fields.has_key?('b64')
197
+ jws.b64 = jws.fields['b64']
198
+ jws.fields = jws.fields.delete('b64')
199
+ return from_fields(jws, modules)
200
+ elsif jws.fields.has_key?('alg') and jws.fields['alg'].is_a?(String)
201
+ alg = modules[:alg] || case
202
+ when jws.fields['alg'].start_with?('ES')
203
+ JOSE::JWS::ALG_ECDSA
204
+ when jws.fields['alg'].start_with?('HS')
205
+ JOSE::JWS::ALG_HMAC
206
+ when jws.fields['alg'].start_with?('PS')
207
+ JOSE::JWS::ALG_RSA_PSS
208
+ when jws.fields['alg'].start_with?('RS')
209
+ JOSE::JWS::ALG_RSA_PKCS1_V1_5
210
+ when jws.fields['alg'] == 'none'
211
+ JOSE::JWS::ALG_none
212
+ else
213
+ raise ArgumentError, "unknown 'alg': #{jws.fields['alg'].inspect}"
214
+ end
215
+ jws.alg, jws.fields = alg.from_map(jws.fields)
216
+ return from_fields(jws, modules)
217
+ elsif jws.alg.nil?
218
+ raise ArgumentError, "missing required keys: 'alg'"
219
+ else
220
+ return jws
221
+ end
222
+ end
223
+
224
+ def signature_to_map(payload, protected_binary, header, key, signature)
225
+ if header and header.is_a?(Hash)
226
+ header = JOSE::Map.new(header)
227
+ end
228
+ header ||= JOSE::Map[]
229
+ if key.is_a?(JOSE::JWK) and key.fields['kid'].is_a?(String)
230
+ header = header.put('kid', key.fields['kid'])
231
+ end
232
+ if header.size == 0
233
+ return JOSE::SignedMap['payload' => payload, 'protected' => protected_binary, 'signature' => signature]
234
+ else
235
+ return JOSE::SignedMap['header' => header.to_hash, 'payload' => payload, 'protected' => protected_binary, 'signature' => signature]
236
+ end
237
+ end
238
+
239
+ end
240
+ end
241
+
242
+ require 'jose/jws/alg'