jose 0.3.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -89,7 +89,7 @@ class JOSE::JWE::ALG_AES_GCM_KW < Struct.new(:cipher_name, :bits, :iv, :tag)
89
89
  end
90
90
 
91
91
  def next_cek(key, enc)
92
- return enc.next_cek
92
+ return enc.next_cek, self
93
93
  end
94
94
 
95
95
  # API functions
@@ -45,7 +45,7 @@ class JOSE::JWE::ALG_AES_KW < Struct.new(:bits)
45
45
  end
46
46
 
47
47
  def next_cek(key, enc)
48
- return enc.next_cek
48
+ return enc.next_cek, self
49
49
  end
50
50
 
51
51
  # API functions
@@ -1,11 +1,11 @@
1
- class JOSE::JWE::ALG_dir
1
+ class JOSE::JWE::ALG_dir < Struct.new(:direct)
2
2
 
3
3
  # JOSE::JWE callbacks
4
4
 
5
5
  def self.from_map(fields)
6
6
  case fields['alg']
7
7
  when 'dir'
8
- return new(), fields.delete('alg')
8
+ return new(true), fields.delete('alg')
9
9
  else
10
10
  raise ArgumentError, "invalid 'alg' for JWE: #{fields['alg'].inspect}"
11
11
  end
@@ -35,9 +35,9 @@ class JOSE::JWE::ALG_dir
35
35
 
36
36
  def next_cek(key, enc)
37
37
  if key.is_a?(String)
38
- return key
38
+ return key, self
39
39
  else
40
- return key.kty.derive_key
40
+ return key.kty.derive_key, self
41
41
  end
42
42
  end
43
43
 
@@ -57,26 +57,31 @@ class JOSE::JWE::ALG_ECDH_ES < Struct.new(:bits, :epk, :apu, :apv)
57
57
 
58
58
  def key_decrypt(box_keys, enc, encrypted_key)
59
59
  other_public_key, my_private_key = box_keys
60
- if my_private_key and epk and epk.to_key != other_public_key.to_key
61
- raise ArgumentError, "other and ephemeral public key mismatch"
62
- elsif epk and my_private_key.nil?
60
+ if my_private_key.nil?
63
61
  my_private_key = other_public_key
64
- other_public_key = epk
65
- else
66
- raise ArgumentError, "missing 'epk' or my_private_key"
62
+ other_public_key = nil
63
+ end
64
+ if epk.nil? and other_public_key.nil?
65
+ raise ArgumentError, "missing 'epk' and 'other_public_key'"
66
+ elsif epk and other_public_key and epk.thumbprint != other_public_key.thumbprint
67
+ raise ArgumentError, "other and ephemeral public key mismatch"
68
+ end
69
+ new_alg = self
70
+ if epk.nil?
71
+ new_alg = JOSE::JWE::ALG_ECDH_ES.new(bits, other_public_key.to_public, apu, apv)
67
72
  end
68
- z = other_public_key.derive_key(my_private_key)
73
+ z = new_alg.epk.derive_key(my_private_key)
69
74
  if bits.nil?
70
75
  algorithm_id = enc.algorithm
71
76
  key_data_len = enc.bits
72
77
  supp_pub_info = [key_data_len].pack('N')
73
- derived_key = JOSE::JWA::ConcatKDF.kdf(OpenSSL::Digest::SHA256, z, [algorithm_id, apu, apv, supp_pub_info], key_data_len)
78
+ derived_key = JOSE::JWA::ConcatKDF.kdf(OpenSSL::Digest::SHA256, z, [algorithm_id, new_alg.apu, new_alg.apv, supp_pub_info], key_data_len)
74
79
  return derived_key
75
80
  else
76
- algorithm_id = algorithm
77
- key_data_len = bits
81
+ algorithm_id = new_alg.algorithm
82
+ key_data_len = new_alg.bits
78
83
  supp_pub_info = [key_data_len].pack('N')
79
- derived_key = JOSE::JWA::ConcatKDF.kdf(OpenSSL::Digest::SHA256, z, [algorithm_id, apu, apv, supp_pub_info], key_data_len)
84
+ derived_key = JOSE::JWA::ConcatKDF.kdf(OpenSSL::Digest::SHA256, z, [algorithm_id, new_alg.apu, new_alg.apv, supp_pub_info], key_data_len)
80
85
  decrypted_key = JOSE::JWA::AES_KW.unwrap(encrypted_key, derived_key)
81
86
  return decrypted_key
82
87
  end
@@ -87,27 +92,49 @@ class JOSE::JWE::ALG_ECDH_ES < Struct.new(:bits, :epk, :apu, :apv)
87
92
  return '', self
88
93
  else
89
94
  other_public_key, my_private_key = box_keys
95
+ if my_private_key.nil?
96
+ raise ArgumentError, "missing 'my_private_key'"
97
+ elsif other_public_key.nil?
98
+ raise ArgumentError, "missing 'other_public_key'"
99
+ elsif epk and my_private_key and epk.thumbprint != my_private_key.thumbprint
100
+ raise ArgumentError, "private and ephemeral public key mismatch"
101
+ end
102
+ new_alg = self
103
+ if epk.nil?
104
+ new_alg = JOSE::JWE::ALG_ECDH_ES.new(bits, my_private_key.to_public, apu, apv)
105
+ end
90
106
  z = other_public_key.derive_key(my_private_key)
91
- algorithm_id = algorithm
92
- key_data_len = bits
107
+ algorithm_id = new_alg.algorithm
108
+ key_data_len = new_alg.bits
93
109
  supp_pub_info = [key_data_len].pack('N')
94
- derived_key = JOSE::JWA::ConcatKDF.kdf(OpenSSL::Digest::SHA256, z, [algorithm_id, apu, apv, supp_pub_info], key_data_len)
110
+ derived_key = JOSE::JWA::ConcatKDF.kdf(OpenSSL::Digest::SHA256, z, [algorithm_id, new_alg.apu, new_alg.apv, supp_pub_info], key_data_len)
95
111
  encrypted_key = JOSE::JWA::AES_KW.wrap(decrypted_key, derived_key)
96
- return encrypted_key, self
112
+ return encrypted_key, new_alg
97
113
  end
98
114
  end
99
115
 
100
116
  def next_cek(box_keys, enc)
101
117
  if bits.nil?
102
118
  other_public_key, my_private_key = box_keys
119
+ if my_private_key.nil?
120
+ raise ArgumentError, "missing 'my_private_key'"
121
+ elsif other_public_key.nil?
122
+ raise ArgumentError, "missing 'other_public_key'"
123
+ elsif epk and my_private_key and epk.thumbprint != my_private_key.thumbprint
124
+ raise ArgumentError, "private and ephemeral public key mismatch"
125
+ end
126
+ new_alg = self
127
+ if epk.nil?
128
+ new_alg = JOSE::JWE::ALG_ECDH_ES.new(bits, my_private_key.to_public, apu, apv)
129
+ end
103
130
  z = other_public_key.derive_key(my_private_key)
104
131
  algorithm_id = enc.algorithm
105
132
  key_data_len = enc.bits
106
133
  supp_pub_info = [key_data_len].pack('N')
107
- derived_key = JOSE::JWA::ConcatKDF.kdf(OpenSSL::Digest::SHA256, z, [algorithm_id, apu, apv, supp_pub_info], key_data_len)
108
- return derived_key
134
+ derived_key = JOSE::JWA::ConcatKDF.kdf(OpenSSL::Digest::SHA256, z, [algorithm_id, new_alg.apu, new_alg.apv, supp_pub_info], key_data_len)
135
+ return derived_key, new_alg
109
136
  else
110
- return enc.next_cek
137
+ return enc.next_cek, self
111
138
  end
112
139
  end
113
140
 
@@ -20,7 +20,7 @@ class JOSE::JWE::ALG_PBES2 < Struct.new(:hmac, :bits, :salt, :iter)
20
20
  end
21
21
  iter = nil
22
22
  if not fields.has_key?('p2c')
23
- iter = 1000
23
+ iter = bits * 32
24
24
  elsif fields['p2c'].is_a?(Integer) and fields['p2c'] >= 0
25
25
  iter = fields['p2c']
26
26
  else
@@ -76,7 +76,7 @@ class JOSE::JWE::ALG_PBES2 < Struct.new(:hmac, :bits, :salt, :iter)
76
76
  end
77
77
  new_alg = self
78
78
  if new_alg.salt.nil?
79
- new_alg = JOSE::JWE::ALG_PBES2.new(hmac, bits, wrap_salt(SecureRandom.random_bytes(8)), iter)
79
+ new_alg = JOSE::JWE::ALG_PBES2.new(hmac, bits, wrap_salt(SecureRandom.random_bytes(bits.div(8))), iter)
80
80
  end
81
81
  derived_key = OpenSSL::PKCS5.pbkdf2_hmac(key, new_alg.salt, new_alg.iter, new_alg.bits.div(8) + (new_alg.bits % 8), new_alg.hmac.new)
82
82
  encrypted_key = JOSE::JWA::AES_KW.wrap(decrypted_key, derived_key)
@@ -84,7 +84,7 @@ class JOSE::JWE::ALG_PBES2 < Struct.new(:hmac, :bits, :salt, :iter)
84
84
  end
85
85
 
86
86
  def next_cek(key, enc)
87
- return enc.next_cek
87
+ return enc.next_cek, self
88
88
  end
89
89
 
90
90
  # API functions
@@ -47,7 +47,7 @@ class JOSE::JWE::ALG_RSA < Struct.new(:rsa_padding, :rsa_oaep_md)
47
47
  end
48
48
 
49
49
  def next_cek(key, enc)
50
- return enc.next_cek
50
+ return enc.next_cek, self
51
51
  end
52
52
 
53
53
  # API functions
@@ -1,8 +1,45 @@
1
1
  module JOSE
2
+ # JWK stands for JSON Web Key which is defined in [RFC 7517](https://tools.ietf.org/html/rfc7517).
2
3
  class JWK < Struct.new(:keys, :kty, :fields)
3
4
 
4
5
  # Decode API
5
6
 
7
+ # Converts a binary or map into a `JOSE.JWK`.
8
+ #
9
+ # !!!ruby
10
+ # JOSE::JWK.from({"k" => "", "kty" => "oct"})
11
+ # # => #<struct JOSE::JWK keys=nil, kty=#<struct JOSE::JWK::KTY_oct oct="">, fields=JOSE::Map[]>
12
+ # JOSE::JWK.from("{\"k\":\"\",\"kty\":\"oct\"}")
13
+ # # => #<struct JOSE::JWK keys=nil, kty=#<struct JOSE::JWK::KTY_oct oct="">, fields=JOSE::Map[]>
14
+ #
15
+ # The `"kty"` field may be overridden with a custom module that implements the {JOSE::JWK::KTY JOSE::JWK::KTY} behaviours.
16
+ #
17
+ # For example:
18
+ #
19
+ # !!!ruby
20
+ # JOSE::JWK.from({ "kty" => "custom" }, { kty: MyCustomKey })
21
+ # # => #<struct JOSE::JWK keys=nil, kty=#<MyCustomKey:0x007f8c5419ff68>, fields=JOSE::Map[]>
22
+ #
23
+ # If a `key` has been specified, it will decrypt an encrypted binary or map into a {JOSE::JWK JOSE::JWK} using the specified `key`.
24
+ #
25
+ # !!!ruby
26
+ # JOSE::JWK.from("eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkExMjhHQ00iLCJwMmMiOjQwOTYsInAycyI6Im5OQ1ZNQUktNTU5UVFtbWRFcnBsZFEifQ.Ucye69ii4dxd1ykNFlJyBVeA6xeNu4aV.2pZ4nBoxBjmdrneS.boqwdFZVNAFHk1M5P6kPYgBUgGwW32QuKzHuFA.wL9Hy6dcE_DPkUW9s5iwKA", "password")
27
+ # # => [#<struct JOSE::JWK keys=nil, kty=#<struct JOSE::JWK::KTY_oct oct="secret">, fields=JOSE::Map[]>,
28
+ # # #<struct JOSE::JWE
29
+ # # alg=
30
+ # # #<struct JOSE::JWE::ALG_PBES2
31
+ # # hmac=OpenSSL::Digest::SHA256,
32
+ # # bits=128,
33
+ # # salt="PBES2-HS256+A128KW\x00\x9C\xD0\x950\x02>\xE7\x9FPBi\x9D\x12\xBAeu",
34
+ # # iter=4096>,
35
+ # # enc=#<struct JOSE::JWE::ENC_AES_GCM cipher_name="aes-128-gcm", bits=128, cek_len=16, iv_len=12>,
36
+ # # zip=nil,
37
+ # # fields=JOSE::Map["cty" => "jwk+json"]>]
38
+ #
39
+ # @param [JOSE::Map, Hash, String, JOSE::JWK, Array<JOSE::Map, Hash, String, JOSE::JWK>] object
40
+ # @param [Hash] modules
41
+ # @param [String] key
42
+ # @return [JOSE::JWK, Array<JOSE::JWK>]
6
43
  def self.from(object, modules = nil, key = nil)
7
44
  case object
8
45
  when JOSE::Map, Hash
@@ -11,11 +48,19 @@ module JOSE
11
48
  return from_binary(object, modules, key)
12
49
  when JOSE::JWK
13
50
  return object
51
+ when Array
52
+ return object.map { |obj| from(obj, modules, key) }
14
53
  else
15
- raise ArgumentError, "'object' must be a Hash, String, or JOSE::JWK"
54
+ raise ArgumentError, "'object' must be a Hash, String, JOSE::JWK, or Array"
16
55
  end
17
56
  end
18
57
 
58
+ # Converts a binary into a {JOSE::JWK JOSE::JWK}.
59
+ #
60
+ # @param [String, Array<String>] object
61
+ # @param [Hash] modules
62
+ # @param [String] key
63
+ # @return [JOSE::JWK, Array<JOSE::JWK>]
19
64
  def self.from_binary(object, modules = nil, key = nil)
20
65
  if (modules.is_a?(String) or modules.is_a?(JOSE::JWK)) and key.nil?
21
66
  key = modules
@@ -30,20 +75,39 @@ module JOSE
30
75
  else
31
76
  return from_map(JOSE.decode(object), modules)
32
77
  end
78
+ when Array
79
+ return object.map { |obj| from_binary(obj, modules, key) }
33
80
  else
34
- raise ArgumentError, "'object' must be a String"
81
+ raise ArgumentError, "'object' must be a String or Array"
35
82
  end
36
83
  end
37
84
 
85
+ # Reads file and calls {.from_binary} to convert into a {JOSE::JWK JOSE::JWK}.
86
+ #
87
+ # @param [String] file
88
+ # @param [Hash] modules
89
+ # @param [String] key
90
+ # @return [JOSE::JWK]
38
91
  def self.from_file(file, modules = nil, key = nil)
39
92
  return from_binary(File.binread(file), modules, key)
40
93
  end
41
94
 
95
+ # Converts Ruby records for EC and RSA keys into a {JOSE::JWK JOSE::JWK}.
96
+ #
97
+ # @param [OpenSSL::PKey] object
98
+ # @param [Hash] modules
99
+ # @return [JOSE::JWK]
42
100
  def self.from_key(object, modules = {})
43
101
  kty = modules[:kty] || JOSE::JWK::KTY
44
102
  return JOSE::JWK.new(nil, *kty.from_key(object))
45
103
  end
46
104
 
105
+ # Converts a map into a {JOSE::JWK JOSE::JWK}.
106
+ #
107
+ # @param [JOSE::Map, Hash, Array<JOSE::Map, Hash>] object
108
+ # @param [Hash] modules
109
+ # @param [String] key
110
+ # @return [JOSE::JWK, Array<JOSE::JWK>]
47
111
  def self.from_map(object, modules = nil, key = nil)
48
112
  if (modules.is_a?(String) or modules.is_a?(JOSE::JWK)) and key.nil?
49
113
  key = modules
@@ -58,34 +122,37 @@ module JOSE
58
122
  else
59
123
  return from_fields(JOSE::JWK.new(nil, nil, JOSE::Map.new(object)), modules)
60
124
  end
125
+ when Array
126
+ return object.map { |obj| from_map(obj, modules, key) }
61
127
  else
62
- raise ArgumentError, "'object' must be a String"
63
- end
64
- end
65
-
66
- def self.from_pem(object, modules = nil, password = nil)
67
- if modules.is_a?(String) and password.nil?
68
- password = modules
69
- modules = {}
128
+ raise ArgumentError, "'object' must be a JOSE::Map, Hash, or Array"
70
129
  end
71
- modules ||= {}
72
- kty = modules[:kty] || JOSE::JWK::PEM
73
- return JOSE::JWK.new(nil, *kty.from_binary(object, password))
74
- end
75
-
76
- def self.from_pem_file(file, modules = nil, password = nil)
77
- return from_pem(File.binread(file), modules, password)
78
130
  end
79
131
 
132
+ # Converts an arbitrary binary into a {JOSE::JWK JOSE::JWK} with `"kty"` of `"oct"`.
133
+ #
134
+ # @param [String] object
135
+ # @param [Hash] modules
136
+ # @return [JOSE::JWK]
80
137
  def self.from_oct(object, modules = {})
81
138
  kty = modules[:kty] || JOSE::JWK::KTY_oct
82
139
  return JOSE::JWK.new(nil, *kty.from_oct(object))
83
140
  end
84
141
 
142
+ # Reads file and calls {JOSE::JWK.from_oct JOSE::JWK.from_oct} to convert into a {JOSE::JWK JOSE::JWK}.
143
+ #
144
+ # @param [String] file
145
+ # @param [Hash] modules
146
+ # @return [JOSE::JWK]
85
147
  def self.from_oct_file(file, modules = {})
86
148
  return from_oct(File.binread(file), modules)
87
149
  end
88
150
 
151
+ # Converts an octet key pair into a {JOSE::JWK JOSE::JWK} with `"kty"` of `"OKP"`.
152
+ #
153
+ # @param [Array] object
154
+ # @param [Hash] modules
155
+ # @return [JOSE::JWK]
89
156
  def self.from_okp(object, modules = {})
90
157
  raise ArgumentError, "object must be an Array of length 2" if not object.is_a?(Array) or object.length != 2
91
158
  kty = modules[:kty] || case object[0]
@@ -107,12 +174,100 @@ module JOSE
107
174
  return JOSE::JWK.new(nil, *kty.from_okp(object))
108
175
  end
109
176
 
177
+ # Converts an openssh key into a {JOSE::JWK JOSE::JWK} with `"kty"` of `"OKP"`.
178
+ #
179
+ # @param [String, Array] object
180
+ # @param [Hash] modules
181
+ # @return [JOSE::JWK]
182
+ def self.from_openssh_key(object, modules = {})
183
+ raise ArgumentError, "object must be a String or Array" if not object.is_a?(String) and not object.is_a?(Array)
184
+ keys = object
185
+ if object.is_a?(String)
186
+ keys = JOSE::JWK::OpenSSHKey.from_binary(object)
187
+ end
188
+ ((pk_type, pk), key), = keys[0]
189
+ sk_type, sk_pk, = key
190
+ if pk_type and pk and key and sk_type and sk_pk and pk_type == sk_type and pk == sk_pk
191
+ kty = modules[:kty] || case pk_type
192
+ when 'ssh-ed25519'
193
+ JOSE::JWK::KTY_OKP_Ed25519
194
+ when 'ssh-ed25519ph'
195
+ JOSE::JWK::KTY_OKP_Ed25519ph
196
+ when 'ssh-ed448'
197
+ JOSE::JWK::KTY_OKP_Ed448
198
+ when 'ssh-ed448ph'
199
+ JOSE::JWK::KTY_OKP_Ed448ph
200
+ when 'ssh-x25519'
201
+ JOSE::JWK::KTY_OKP_X25519
202
+ when 'ssh-x448'
203
+ JOSE::JWK::KTY_OKP_X448
204
+ else
205
+ raise ArgumentError, "unrecognized openssh key type: #{pk_type.inspect}"
206
+ end
207
+ return JOSE::JWK.new(nil, *kty.from_openssh_key(key))
208
+ else
209
+ raise ArgumentError, "unrecognized openssh key format"
210
+ end
211
+ end
212
+
213
+ # Reads file and calls {JOSE::JWK.from_openssh_key JOSE::JWK.from_openssh_key} to convert into a {JOSE::JWK JOSE::JWK}.
214
+ #
215
+ # @param [String] file
216
+ # @param [Hash] modules
217
+ # @return [JOSE::JWK]
218
+ def self.from_openssh_key_file(file, modules = {})
219
+ return from_openssh_key(File.binread(file), modules)
220
+ end
221
+
222
+ # Converts a PEM (Privacy Enhanced Email) binary into a {JOSE::JWK JOSE::JWK}.
223
+ #
224
+ # If `password` is present, decrypts an encrypted PEM (Privacy Enhanced Email) binary into a {JOSE::JWK JOSE::JWK} using `password`.
225
+ #
226
+ # @param [String] object
227
+ # @param [Hash] modules
228
+ # @param [String] password
229
+ # @return [JOSE::JWK]
230
+ def self.from_pem(object, modules = nil, password = nil)
231
+ if modules.is_a?(String) and password.nil?
232
+ password = modules
233
+ modules = {}
234
+ end
235
+ modules ||= {}
236
+ kty = modules[:kty] || JOSE::JWK::PEM
237
+ return JOSE::JWK.new(nil, *kty.from_binary(object, password))
238
+ end
239
+
240
+ # Reads file and calls {JOSE::JWK.from_pem JOSE::JWK.from_pem} to convert into a {JOSE::JWK JOSE::JWK}.
241
+ #
242
+ # @param [String] file
243
+ # @param [Hash] modules
244
+ # @param [String] password
245
+ # @return [JOSE::JWK]
246
+ def self.from_pem_file(file, modules = nil, password = nil)
247
+ return from_pem(File.binread(file), modules, password)
248
+ end
249
+
110
250
  # Encode API
111
251
 
252
+ # Converts a {JOSE::JWK JOSE::JWK} into a binary.
253
+ #
254
+ # @param [JOSE::JWK, Array<JOSE::JWK>] jwk
255
+ # @param [String] key
256
+ # @param [JOSE::JWE] jwe
257
+ # @return [String, JOSE::EncryptedBinary, Array<String, JOSE::EncryptedBinary>]
112
258
  def self.to_binary(jwk, key = nil, jwe = nil)
113
- return from(jwk).to_binary(key, jwe)
259
+ if jwk.is_a?(Array)
260
+ return jwk.map { |obj| from(obj).to_binary(key, jwe) }
261
+ else
262
+ return from(jwk).to_binary(key, jwe)
263
+ end
114
264
  end
115
265
 
266
+ # Converts a {JOSE::JWK JOSE::JWK} into a binary.
267
+ #
268
+ # @param [String] key
269
+ # @param [JOSE::JWE] jwe
270
+ # @return [String, JOSE::EncryptedBinary]
116
271
  def to_binary(key = nil, jwe = nil)
117
272
  if not key.nil?
118
273
  jwe ||= kty.key_encryptor(fields, key)
@@ -124,26 +279,61 @@ module JOSE
124
279
  end
125
280
  end
126
281
 
282
+ # Calls {JOSE::JWK.to_binary JOSE::JWK.to_binary} on a {JOSE::JWK JOSE::JWK} and then writes the binary to `file`.
283
+ #
284
+ # @param [JOSE::Map, Hash, String, JOSE::JWK] jwk
285
+ # @param [String] file
286
+ # @param [String] key
287
+ # @param [JOSE::JWE] jwe
288
+ # @return [Fixnum] bytes written
127
289
  def self.to_file(jwk, file, key = nil, jwe = nil)
128
290
  return from(jwk).to_file(file, key, jwe)
129
291
  end
130
292
 
293
+ # Calls {JOSE::JWK.to_binary JOSE::JWK.to_binary} on a {JOSE::JWK JOSE::JWK} and then writes the binary to `file`.
294
+ #
295
+ # @param [String] file
296
+ # @param [String] key
297
+ # @param [JOSE::JWE] jwe
298
+ # @return [Fixnum] bytes written
131
299
  def to_file(file, key = nil, jwe = nil)
132
300
  return File.binwrite(file, to_binary(key, jwe))
133
301
  end
134
302
 
303
+ # Converts a {JOSE::JWK JOSE::JWK} into the raw key format.
304
+ #
305
+ # @param [JOSE::JWK] jwk
306
+ # @return [OpenSSL::PKey, Object]
135
307
  def self.to_key(jwk)
136
308
  return from(jwk).to_key
137
309
  end
138
310
 
311
+ # Converts a {JOSE::JWK JOSE::JWK} into the raw key format.
312
+ #
313
+ # @return [OpenSSL::PKey, Object]
139
314
  def to_key
140
315
  return kty.to_key
141
316
  end
142
317
 
318
+ # Converts a {JOSE::JWK JOSE::JWK} into a map.
319
+ #
320
+ # @param [JOSE::Map, Hash, String, JOSE::JWK, Array<JOSE::Map, Hash, String, JOSE::JWK>] jwk
321
+ # @param [String] key
322
+ # @param [JOSE::JWE] jwe
323
+ # @return [JOSE::Map, Array<JOSE::Map>]
143
324
  def self.to_map(jwk, key = nil, jwe = nil)
144
- return from(jwk).to_map(key, jwe)
325
+ if jwk.is_a?(Array)
326
+ return from(jwk).map { |obj| obj.to_map(key, jwe) }
327
+ else
328
+ return from(jwk).to_map(key, jwe)
329
+ end
145
330
  end
146
331
 
332
+ # Converts a {JOSE::JWK JOSE::JWK} into a map.
333
+ #
334
+ # @param [String] key
335
+ # @param [JOSE::JWE] jwe
336
+ # @return [JOSE::Map]
147
337
  def to_map(key = nil, jwe = nil)
148
338
  if not key.nil?
149
339
  jwe ||= kty.key_encryptor(fields, key)
@@ -155,98 +345,363 @@ module JOSE
155
345
  end
156
346
  end
157
347
 
348
+ # Converts a {JOSE::JWK JOSE::JWK} into a raw binary octet.
349
+ #
350
+ # @param [JOSE::Map, Hash, String, JOSE::JWK, Array<JOSE::Map, Hash, String, JOSE::JWK>] jwk
351
+ # @return [String, Array<String>]
158
352
  def self.to_oct(jwk)
159
- return from(jwk).to_oct
353
+ if jwk.is_a?(Array)
354
+ return from(jwk).map { |obj| obj.to_oct }
355
+ else
356
+ return from(jwk).to_oct
357
+ end
160
358
  end
161
359
 
360
+ # Converts a {JOSE::JWK JOSE::JWK} into a raw binary octet.
361
+ #
362
+ # @return [String]
162
363
  def to_oct
163
364
  return kty.to_oct
164
365
  end
165
366
 
367
+ # Calls {JOSE::JWK.to_oct JOSE::JWK.to_oct} on a {JOSE::JWK JOSE::JWK} and then writes the binary to `file`.
368
+ #
369
+ # @param [JOSE::Map, Hash, String, JOSE::JWK] jwk
370
+ # @param [String] file
371
+ # @return [Fixnum] bytes written
372
+ def self.to_oct_file(jwk, file)
373
+ return from(jwk).to_file(file)
374
+ end
375
+
376
+ # Calls {JOSE::JWK#to_oct JOSE::JWK#to_oct} on a {JOSE::JWK JOSE::JWK} and then writes the binary to `file`.
377
+ #
378
+ # @param [String] file
379
+ # @return [Fixnum] bytes written
380
+ def to_oct_file(file)
381
+ return File.binwrite(file, to_oct)
382
+ end
383
+
384
+ # Converts a {JOSE::JWK JOSE::JWK} into an octet key pair.
385
+ #
386
+ # @param [JOSE::Map, Hash, String, JOSE::JWK, Array<JOSE::Map, Hash, String, JOSE::JWK>] jwk
387
+ # @return [Object, Array<Object>]
166
388
  def self.to_okp(jwk)
167
- return from(jwk).to_okp
389
+ if jwk.is_a?(Array)
390
+ return from(jwk).map { |obj| obj.to_okp }
391
+ else
392
+ return from(jwk).to_okp
393
+ end
168
394
  end
169
395
 
396
+ # Converts a {JOSE::JWK JOSE::JWK} into an octet key pair.
397
+ #
398
+ # @return [String]
170
399
  def to_okp
171
400
  return kty.to_okp
172
401
  end
173
402
 
403
+ # Converts a {JOSE::JWK JOSE::JWK} into an OpenSSH key binary.
404
+ #
405
+ # @param [JOSE::Map, Hash, String, JOSE::JWK, Array<JOSE::Map, Hash, String, JOSE::JWK>] jwk
406
+ # @return [Object, Array<Object>]
407
+ def self.to_openssh_key(jwk)
408
+ if jwk.is_a?(Array)
409
+ return from(jwk).map { |obj| obj.to_openssh_key }
410
+ else
411
+ return from(jwk).to_openssh_key
412
+ end
413
+ end
414
+
415
+ # Converts a {JOSE::JWK JOSE::JWK} into an OpenSSH key binary.
416
+ #
417
+ # @return [Object]
418
+ def to_openssh_key
419
+ return kty.to_openssh_key(fields)
420
+ end
421
+
422
+ # Calls {JOSE::JWK.to_openssh_key JOSE::JWK.to_openssh_key} on a {JOSE::JWK JOSE::JWK} and then writes the binary to `file`.
423
+ #
424
+ # @param [JOSE::Map, Hash, String, JOSE::JWK] jwk
425
+ # @param [String] file
426
+ # @return [Fixnum] bytes written
427
+ def self.to_openssh_key_file(jwk, file)
428
+ return from(jwk).to_file(file)
429
+ end
430
+
431
+ # Calls {JOSE::JWK#to_openssh_key JOSE::JWK#to_openssh_key} on a {JOSE::JWK JOSE::JWK} and then writes the binary to `file`.
432
+ #
433
+ # @param [String] file
434
+ # @return [Fixnum] bytes written
435
+ def to_openssh_key_file(file)
436
+ return File.binwrite(file, to_openssh_key)
437
+ end
438
+
439
+ # Converts a {JOSE::JWK JOSE::JWK} into a PEM (Privacy Enhanced Email) binary.
440
+ #
441
+ # @param [JOSE::Map, Hash, String, JOSE::JWK, Array<JOSE::Map, Hash, String, JOSE::JWK>] jwk
442
+ # @param [String] password
443
+ # @return [String, Array<String>]
174
444
  def self.to_pem(jwk, password = nil)
175
- return from(jwk).to_pem(password)
445
+ if jwk.is_a?(Array)
446
+ return from(jwk).map { |obj| obj.to_pem(password) }
447
+ else
448
+ return from(jwk).to_pem(password)
449
+ end
176
450
  end
177
451
 
452
+ # Converts a {JOSE::JWK JOSE::JWK} into a PEM (Privacy Enhanced Email) binary.
453
+ #
454
+ # @param [String] password
455
+ # @return [String]
178
456
  def to_pem(password = nil)
179
457
  return kty.to_pem(password)
180
458
  end
181
459
 
460
+ # Calls {JOSE::JWK.to_pem JOSE::JWK.to_pem} on a {JOSE::JWK JOSE::JWK} and then writes the binary to `file`.
461
+ #
462
+ # @param [JOSE::Map, Hash, String, JOSE::JWK] jwk
463
+ # @param [String] file
464
+ # @param [String] password
465
+ # @return [Fixnum] bytes written
466
+ def self.to_pem_file(jwk, file, password = nil)
467
+ return from(jwk).to_file(file, password)
468
+ end
469
+
470
+ # Calls {JOSE::JWK#to_pem JOSE::JWK#to_pem} on a {JOSE::JWK JOSE::JWK} and then writes the binary to `file`.
471
+ #
472
+ # @param [String] file
473
+ # @param [String] password
474
+ # @return [Fixnum] bytes written
475
+ def to_pem_file(file, password = nil)
476
+ return File.binwrite(file, to_pem(password))
477
+ end
478
+
479
+ # Converts a private {JOSE::JWK JOSE::JWK} into a public {JOSE::JWK JOSE::JWK}.
480
+ #
481
+ # !!!ruby
482
+ # jwk_rsa = JOSE::JWK.generate_key([:rsa, 256]).to_map
483
+ # # => JOSE::Map[
484
+ # # "dq" => "Iv_BghpjRyv8hk4AgsX_3w",
485
+ # # "e" => "AQAB",
486
+ # # "d" => "imiCh2gK77pDAa_NuQbHN1hZdLY0eTl8tp4WLfe1uQ0",
487
+ # # "p" => "-eKE_wk7O5JWw_1fw-rciw",
488
+ # # "qi" => "MqCwIoTTCkYmGQHsOM7IuA",
489
+ # # "n" => "vj2WbxlGF1yU9SoQJMqKw6c2asTks_cVuXEAO3x_yOU",
490
+ # # "kty" => "RSA",
491
+ # # "q" => "wuVog_0-60w7_56y8wZuTw",
492
+ # # "dp" => "lU_9GEdz1UzD-6hSqMaVsQ"]
493
+ # JOSE::JWK.to_public(jwk_rsa).to_map
494
+ # # => JOSE::Map[
495
+ # # "e" => "AQAB",
496
+ # # "n" => "vj2WbxlGF1yU9SoQJMqKw6c2asTks_cVuXEAO3x_yOU",
497
+ # # "kty" => "RSA"]
498
+ #
499
+ # @param [JOSE::Map, Hash, String, JOSE::JWK, Array<JOSE::Map, Hash, String, JOSE::JWK>] jwk
500
+ # @return [JOSE::JWK, Array<JOSE::JWK>]
182
501
  def self.to_public(jwk)
183
- return from(jwk).to_public
502
+ if jwk.is_a?(Array)
503
+ return from(jwk).map { |obj| obj.to_public }
504
+ else
505
+ return from(jwk).to_public
506
+ end
184
507
  end
185
508
 
509
+ # Converts a private {JOSE::JWK JOSE::JWK} into a public {JOSE::JWK JOSE::JWK}.
510
+ #
511
+ # @see JOSE::JWK.to_public
512
+ # @return [JOSE::JWK]
186
513
  def to_public
187
514
  return JOSE::JWK.from_map(to_public_map)
188
515
  end
189
516
 
517
+ # Calls {JOSE::JWK.to_binary JOSE::JWK.to_binary} on a {JOSE::JWK JOSE::JWK} and then writes the binary to `file`.
518
+ #
519
+ # @param [JOSE::Map, Hash, String, JOSE::JWK] jwk
520
+ # @param [String] file
521
+ # @return [Fixnum] bytes written
522
+ def self.to_public_file(jwk, file)
523
+ return from(jwk).to_public_file(file)
524
+ end
525
+
526
+ # Calls {JOSE::JWK.to_public JOSE::JWK.to_public} on a {JOSE::JWK JOSE::JWK} and then writes the binary to `file`.
527
+ #
528
+ # @param [String] file
529
+ # @return [Fixnum] bytes written
530
+ def to_public_file(file)
531
+ return File.binwrite(file, to_public.to_binary)
532
+ end
533
+
534
+ # Calls {JOSE::JWK.to_public JOSE::JWK.to_public} and then {JOSE::JWK.to_key JOSE::JWK.to_key} on a {JOSE::JWK JOSE::JWK}.
535
+ #
536
+ # @param [JOSE::Map, Hash, String, JOSE::JWK, Array<JOSE::Map, Hash, String, JOSE::JWK>] jwk
537
+ # @return [OpenSSL::PKey, Object, Array<OpenSSL::PKey, Object>]
190
538
  def self.to_public_key(jwk)
191
- return from(jwk).to_public_key
539
+ if jwk.is_a?(Array)
540
+ return from(jwk).map { |obj| obj.to_public_key }
541
+ else
542
+ return from(jwk).to_public_key
543
+ end
192
544
  end
193
545
 
546
+ # Calls {JOSE::JWK#to_public JOSE::JWK#to_public} and then {JOSE::JWK#to_key JOSE::JWK#to_key} on a {JOSE::JWK JOSE::JWK}.
547
+ #
548
+ # @return [OpenSSL::PKey, Object]
194
549
  def to_public_key
195
550
  return to_public.to_key
196
551
  end
197
552
 
553
+ # Calls {JOSE::JWK.to_public JOSE::JWK.to_public} and then {JOSE::JWK.to_map JOSE::JWK.to_map} on a {JOSE::JWK JOSE::JWK}.
554
+ #
555
+ # @param [JOSE::Map, Hash, String, JOSE::JWK, Array<JOSE::Map, Hash, String, JOSE::JWK>] jwk
556
+ # @return [JOSE::Map, Array<JOSE::Map>]
198
557
  def self.to_public_map(jwk)
199
- return from(jwk).to_public_map
558
+ if jwk.is_a?(Array)
559
+ return from(jwk).map { |obj| obj.to_public_map }
560
+ else
561
+ return from(jwk).to_public_map
562
+ end
200
563
  end
201
564
 
565
+ # Calls {JOSE::JWK#to_public JOSE::JWK#to_public} and then {JOSE::JWK#to_map JOSE::JWK#to_map} on a {JOSE::JWK JOSE::JWK}.
566
+ #
567
+ # @return [JOSE::Map]
202
568
  def to_public_map
203
569
  return kty.to_public_map(fields)
204
570
  end
205
571
 
572
+ # Converts a {JOSE::JWK JOSE::JWK} into a map that can be used by {JOSE::JWK.thumbprint JOSE::JWK.thumbprint}.
573
+ #
574
+ # @param [JOSE::Map, Hash, String, JOSE::JWK, Array<JOSE::Map, Hash, String, JOSE::JWK>] jwk
575
+ # @return [JOSE::Map, Array<JOSE::Map>]
206
576
  def self.to_thumbprint_map(jwk)
207
- return from(jwk).to_thumbprint_map
577
+ if jwk.is_a?(Array)
578
+ return from(jwk).map { |obj| obj.to_thumbprint_map }
579
+ else
580
+ return from(jwk).to_thumbprint_map
581
+ end
208
582
  end
209
583
 
584
+ # Converts a {JOSE::JWK JOSE::JWK} into a map that can be used by {JOSE::JWK.thumbprint JOSE::JWK.thumbprint}.
585
+ #
586
+ # @return [JOSE::Map]
210
587
  def to_thumbprint_map
211
588
  return kty.to_thumbprint_map(fields)
212
589
  end
213
590
 
214
591
  # API
215
592
 
593
+ # Decrypts the `encrypted` binary or map using the `jwk`.
594
+ #
595
+ # @see JOWE::JWE.block_decrypt
596
+ # @param [JOSE::JWK] jwk
597
+ # @param [JOSE::EncryptedBinary, JOSE::EncryptedMap] encrypted
598
+ # @return [[String, JOSE::JWE]]
216
599
  def self.block_decrypt(jwk, encrypted)
217
600
  return from(jwk).block_decrypt(encrypted)
218
601
  end
219
602
 
603
+ # Decrypts the `encrypted` binary or map using the `jwk`.
604
+ #
605
+ # @see JOWE::JWE.block_decrypt
606
+ # @param [JOSE::EncryptedBinary, JOSE::EncryptedMap] encrypted
607
+ # @return [[String, JOSE::JWE]]
220
608
  def block_decrypt(encrypted)
221
609
  return JOSE::JWE.block_decrypt(self, encrypted)
222
610
  end
223
611
 
612
+ # Encrypts the `plain_text` using the `jwk` and algorithms specified by the `jwe`.
613
+ #
614
+ # @see JOSE::JWE.block_encrypt
615
+ # @param [JOSE::JWK] jwk
616
+ # @param [String] plain_text
617
+ # @param [JOSE::JWE] jwe
618
+ # @return [JOSE::EncryptedMap]
224
619
  def self.block_encrypt(jwk, plain_text, jwe = nil)
225
620
  return from(jwk).block_encrypt(plain_text, jwe)
226
621
  end
227
622
 
623
+ # Encrypts the `plain_text` using the `jwk` and algorithms specified by the `jwe`.
624
+ #
625
+ # @see JOSE::JWE.block_encrypt
626
+ # @param [String] plain_text
627
+ # @param [JOSE::JWE] jwe
628
+ # @return [JOSE::EncryptedMap]
228
629
  def block_encrypt(plain_text, jwe = nil)
229
630
  jwe ||= block_encryptor
230
631
  return JOSE::JWE.block_encrypt(self, plain_text, jwe)
231
632
  end
232
633
 
233
- def self.block_encryptor(jwe)
234
- return from(jwe).block_encryptor
634
+ # Returns a block encryptor map for the key type.
635
+ #
636
+ # @param [JOSE::JWK, Array<JOSE::JWK>] jwk
637
+ # @return [JOSE::Map, Array<JOSE::Map>]
638
+ def self.block_encryptor(jwk)
639
+ if jwk.is_a?(Array)
640
+ return from(jwk).map { |obj| obj.block_encryptor }
641
+ else
642
+ return from(jwk).block_encryptor
643
+ end
235
644
  end
236
645
 
646
+ # Returns a block encryptor map for the key type.
647
+ #
648
+ # @return [JOSE::Map]
237
649
  def block_encryptor
238
650
  return kty.block_encryptor(fields)
239
651
  end
240
652
 
241
- def self.box_decrypt(jwk, encrypted)
242
- return from(jwk).box_decrypt(encrypted)
653
+ # Key Agreement decryption of the `encrypted` binary or map using `my_private_jwk`.
654
+ #
655
+ # @see JOSE::JWK.box_encrypt
656
+ # @see JOSE::JWE.block_decrypt
657
+ # @param [JOSE::JWK] jwk
658
+ # @param [JOSE::EncryptedBinary, JOSE::EncryptedMap] encrypted
659
+ # @param [JOSE::JWK] public_jwk
660
+ # @return [[String, JOSE::JWE]]
661
+ def self.box_decrypt(jwk, encrypted, public_jwk = nil)
662
+ return from(jwk).box_decrypt(encrypted, public_jwk)
243
663
  end
244
664
 
245
- def box_decrypt(encrypted)
246
- return JOSE::JWE.block_decrypt(self, encrypted)
665
+ # Key Agreement decryption of the `encrypted` binary or map using `my_private_jwk`.
666
+ #
667
+ # @see JOSE::JWK.box_encrypt
668
+ # @see JOSE::JWE.block_decrypt
669
+ # @param [JOSE::EncryptedBinary, JOSE::EncryptedMap] encrypted
670
+ # @param [JOSE::JWK] public_jwk
671
+ # @return [[String, JOSE::JWE]]
672
+ def box_decrypt(encrypted, public_jwk = nil)
673
+ if public_jwk
674
+ return JOSE::JWE.block_decrypt([public_jwk, self], encrypted)
675
+ else
676
+ return JOSE::JWE.block_decrypt(self, encrypted)
677
+ end
247
678
  end
248
679
 
249
- # Generates an ephemeral private key based on other public key curve.
680
+ # Key Agreement encryption of `plain_text` by generating an ephemeral private key based on `other_public_jwk` curve.
681
+ #
682
+ # If no private key has been specified in `box_keys`, it generates an ephemeral private key based on other public key curve.
683
+ #
684
+ # @see JOSE::JWK.box_decrypt
685
+ # @see JOSE::JWE.block_encrypt
686
+ # @param [String] plain_text
687
+ # @param [JOSE::JWK, [JOSE::JWK, JOSE::JWK]] box_keys
688
+ # @param [JOSE::JWE] jwe
689
+ # @return [JOSE::EncryptedMap, [JOSE::EncryptedMap, JOSE::JWK]]
690
+ def self.box_encrypt(plain_text, box_keys, jwe = nil)
691
+ other_public_key, my_private_key = box_keys
692
+ return from(other_public_key).box_encrypt(plain_text, my_private_jwk, jwe)
693
+ end
694
+
695
+ # Key Agreement encryption of `plain_text` by generating an ephemeral private key based on `other_public_jwk` curve.
696
+ #
697
+ # If no private key has been specified in `my_private_key`, it generates an ephemeral private key based on other public key curve.
698
+ #
699
+ # @see JOSE::JWK.box_decrypt
700
+ # @see JOSE::JWE.block_encrypt
701
+ # @param [String] plain_text
702
+ # @param [JOSE::JWK] my_private_jwk
703
+ # @param [JOSE::JWE] jwe
704
+ # @return [JOSE::EncryptedMap, [JOSE::EncryptedMap, JOSE::JWK]]
250
705
  def box_encrypt(plain_text, my_private_jwk = nil, jwe = nil)
251
706
  generated_jwk = nil
252
707
  other_public_jwk = self
@@ -280,10 +735,32 @@ module JOSE
280
735
  end
281
736
  end
282
737
 
738
+ # Derives a key (typically just returns a binary representation of the key).
739
+ #
740
+ # @param [*Object] args
741
+ # @return [String]
283
742
  def derive_key(*args)
284
743
  return kty.derive_key(*args)
285
744
  end
286
745
 
746
+ # Generates a new {JOSE::JWK JOSE::JWK} based on another {JOSE::JWK JOSE::JWK} or from initialization params provided.
747
+ #
748
+ # Passing another {JOSE::JWK JOSE::JWK} results in different behavior depending on the `"kty"`:
749
+ #
750
+ # * `"EC"` - uses the same named curve to generate a new key
751
+ # * `"oct"` - uses the byte size to generate a new key
752
+ # * `"OKP"` - uses the named curve to generate a new key
753
+ # * `"RSA"` - uses the same modulus and exponent sizes to generate a new key
754
+ #
755
+ # The following initialization params may also be used:
756
+ #
757
+ # * `[:ec, "P-256" | "P-384" | "P-521"]` - generates an `"EC"` key using the `"P-256"`, `"P-384"`, or `"P-521"` curves
758
+ # * `[:oct, bytes]` - generates an `"oct"` key made of a random `bytes` number of bytes
759
+ # * `[:okp, :Ed25519 | :Ed25519ph | :Ed448 | :Ed448ph | :X25519 | :X448]` - generates an `"OKP"` key using the specified curve
760
+ # * `[:rsa, modulus_size] | [:rsa, modulus_size, exponent_size]` - generates an `"RSA"` key using the `modulus_size` and `exponent_size`
761
+ #
762
+ # @param [Array] params
763
+ # @return [JOSE::JWK]
287
764
  def self.generate_key(params)
288
765
  if params.is_a?(Array) and (params.length == 2 or params.length == 3)
289
766
  case params[0]
@@ -322,14 +799,24 @@ module JOSE
322
799
  end
323
800
  end
324
801
 
802
+ # Generates a new key based on the current one.
803
+ #
804
+ # @return [JOSE::JWK]
325
805
  def generate_key
326
806
  return JOSE::JWK.new(nil, *kty.generate_key(fields))
327
807
  end
328
808
 
809
+ # Merges map on right into map on left.
810
+ # @param [JOSE::Map, Hash, String, JOSE::JWK] left
811
+ # @param [JOSE::Map, Hash, String, JOSE::JWK] right
812
+ # @return [JOSE::JWK]
329
813
  def self.merge(left, right)
330
814
  return from(left).merge(right)
331
815
  end
332
816
 
817
+ # Merges object into current map.
818
+ # @param [JOSE::Map, Hash, String, JOSE::JWK] object
819
+ # @return [JOSE::JWK]
333
820
  def merge(object)
334
821
  object = case object
335
822
  when JOSE::Map, Hash
@@ -344,10 +831,23 @@ module JOSE
344
831
  return JOSE::JWK.from_map(self.to_map.merge(object))
345
832
  end
346
833
 
834
+ # Computes the shared secret between two keys.
835
+ #
836
+ # Currently only works for `"EC"` keys and `"OKP"` keys with `"crv"` set to `"X25519"` or `"X448"`.
837
+ #
838
+ # @param [JOSE::JWK] your_jwk
839
+ # @param [JOSE::JWK] my_jwk
840
+ # @return [String]
347
841
  def self.shared_secret(your_jwk, my_jwk)
348
842
  return from(your_jwk).shared_secret(from(my_jwk))
349
843
  end
350
844
 
845
+ # Computes the shared secret between two keys.
846
+ #
847
+ # Currently only works for `"EC"` keys and `"OKP"` keys with `"crv"` set to `"X25519"` or `"X448"`.
848
+ #
849
+ # @param [JOSE::JWK] other_jwk
850
+ # @return [String]
351
851
  def shared_secret(other_jwk)
352
852
  other_jwk = from(other_jwk) if not other_jwk.is_a?(JOSE::JWK)
353
853
  raise ArgumentError, "key types must match" if other_jwk.kty.class != kty.class
@@ -355,54 +855,144 @@ module JOSE
355
855
  return kty.derive_key(other_jwk)
356
856
  end
357
857
 
858
+ # Signs the `plain_text` using the `jwk` and the default signer algorithm `jws` for the key type.
859
+ #
860
+ # @see JOSE::JWS.sign
861
+ # @param [JOSE::JWK] jwk
862
+ # @param [String] plain_text
863
+ # @param [JOSE::JWS] jws
864
+ # @param [JOSE::Map] header
865
+ # @return [JOSE::SignedMap]
358
866
  def self.sign(jwk, plain_text, jws = nil, header = nil)
359
867
  return from(jwk).sign(plain_text, jws, header)
360
868
  end
361
869
 
870
+ # Signs the `plain_text` using the `jwk` and the default signer algorithm `jws` for the key type.
871
+ #
872
+ # @see JOSE::JWS.sign
873
+ # @param [String] plain_text
874
+ # @param [JOSE::JWS] jws
875
+ # @param [JOSE::Map] header
876
+ # @return [JOSE::SignedMap]
362
877
  def sign(plain_text, jws = nil, header = nil)
363
878
  jws ||= signer
364
879
  return JOSE::JWS.sign(self, plain_text, jws, header)
365
880
  end
366
881
 
882
+ # Returns a signer map for the key type.
883
+ #
884
+ # @param [JOSE::JWK] jwk
885
+ # @return [JOSE::Map]
367
886
  def self.signer(jwk)
368
887
  return from(jwk).signer
369
888
  end
370
889
 
890
+ # Returns a signer map for the key type.
891
+ #
892
+ # @return [JOSE::Map]
371
893
  def signer
372
894
  return kty.signer(fields)
373
895
  end
374
896
 
897
+ # Returns the unique thumbprint for a {JOSE::JWK JOSE::JWK} using the `digest_type`.
898
+ #
899
+ # !!!ruby
900
+ # # let's define two different keys that will have the same thumbprint
901
+ # jwk1 = JOSE::JWK.from_oct("secret")
902
+ # jwk2 = JOSE::JWK.from({ "use" => "sig", "k" => "c2VjcmV0", "kty" => "oct" })
903
+ #
904
+ # JOSE::JWK.thumbprint(jwk1)
905
+ # # => "DWBh0SEIAPYh1x5uvot4z3AhaikHkxNJa3Ada2fT-Cg"
906
+ # JOSE::JWK.thumbprint(jwk2)
907
+ # # => "DWBh0SEIAPYh1x5uvot4z3AhaikHkxNJa3Ada2fT-Cg"
908
+ # JOSE::JWK.thumbprint('MD5', jwk1)
909
+ # # => "Kldz8k5PQm7y1E3aNBlMiA"
910
+ # JOSE::JWK.thumbprint('MD5', jwk2)
911
+ # # => "Kldz8k5PQm7y1E3aNBlMiA"
912
+ #
913
+ # @see https://tools.ietf.org/html/rfc7638 RFC 7638 - JSON Web Key (JWK) Thumbprint
914
+ # @param [String] digest_type
915
+ # @param [JOSE::JWK] jwk
916
+ # @return [String]
917
+ def self.thumbprint(digest_type, jwk = nil)
918
+ if jwk.nil?
919
+ jwk = digest_type
920
+ digest_type = nil
921
+ end
922
+ return from(jwk).thumbprint(digest_type)
923
+ end
924
+
925
+ # Returns the unique thumbprint for a {JOSE::JWK JOSE::JWK} using the `digest_type`.
926
+ #
927
+ # @see JOSE::JWK.thumbprint
928
+ # @see https://tools.ietf.org/html/rfc7638 RFC 7638 - JSON Web Key (JWK) Thumbprint
929
+ # @param [String] digest_type
930
+ # @return [String]
931
+ def thumbprint(digest_type = nil)
932
+ digest_type ||= 'SHA256'
933
+ thumbprint_binary = JOSE.encode(to_thumbprint_map)
934
+ return JOSE.urlsafe_encode64(OpenSSL::Digest.new(digest_type).digest(thumbprint_binary))
935
+ end
936
+
937
+ # Returns a verifier algorithm list for the key type.
938
+ #
939
+ # @param [JOSE::JWK] jwk
940
+ # @return [Array<String>]
941
+ def self.verifier(jwk)
942
+ if jwk.is_a?(Array)
943
+ return from(jwk).map { |obj| obj.verifier }
944
+ else
945
+ return from(jwk).verifier
946
+ end
947
+ end
948
+
949
+ # Returns a verifier algorithm list for the key type.
950
+ #
951
+ # @return [Array<String>]
952
+ def verifier
953
+ return kty.verifier(fields)
954
+ end
955
+
956
+ # Verifies the `signed` using the `jwk`.
957
+ #
958
+ # @see JOSE::JWS.verify
959
+ # @param [JOSE::SignedBinary, JOSE::SignedMap] signed
960
+ # @param [JOSE::JWK] jwk
961
+ # @return [[Boolean, String, JOSE::JWS]]
375
962
  def self.verify(signed, jwk)
376
963
  return from(jwk).verify(signed)
377
964
  end
378
965
 
966
+ # Verifies the `signed` using the `jwk`.
967
+ #
968
+ # @see JOSE::JWS.verify
969
+ # @param [JOSE::SignedBinary, JOSE::SignedMap] signed
970
+ # @return [[Boolean, String, JOSE::JWS]]
379
971
  def verify(signed)
380
972
  return JOSE::JWS.verify(self, signed)
381
973
  end
382
974
 
975
+ # Verifies the `signed` using the `jwk` and whitelists the `"alg"` using `allow`.
976
+ #
977
+ # @see JOSE::JWS.verify_strict
978
+ # @param [JOSE::SignedBinary, JOSE::SignedMap] signed
979
+ # @param [Array<String>] allow
980
+ # @param [JOSE::JWK] jwk
981
+ # @return [[Boolean, String, JOSE::JWS]]
383
982
  def self.verify_strict(signed, allow, jwk)
384
983
  return from(jwk).verify_strict(signed, allow)
385
984
  end
386
985
 
986
+ # Verifies the `signed` using the `jwk` and whitelists the `"alg"` using `allow`.
987
+ #
988
+ # @see JOSE::JWS.verify_strict
989
+ # @param [JOSE::SignedBinary, JOSE::SignedMap] signed
990
+ # @param [Array<String>] allow
991
+ # @return [[Boolean, String, JOSE::JWS]]
387
992
  def verify_strict(signed, allow)
388
993
  return JOSE::JWS.verify_strict(self, allow, signed)
389
994
  end
390
995
 
391
- # See https://tools.ietf.org/html/rfc7638
392
- def self.thumbprint(digest_type, jwk = nil)
393
- if jwk.nil?
394
- jwk = digest_type
395
- digest_type = nil
396
- end
397
- return from(jwk).thumbprint(digest_type)
398
- end
399
-
400
- def thumbprint(digest_type = nil)
401
- digest_type ||= 'SHA256'
402
- thumbprint_binary = JOSE.encode(to_thumbprint_map)
403
- return JOSE.urlsafe_encode64(OpenSSL::Digest.new(digest_type).digest(thumbprint_binary))
404
- end
405
-
406
996
  private
407
997
 
408
998
  def self.from_fields(jwk, modules)
@@ -451,5 +1041,6 @@ module JOSE
451
1041
  end
452
1042
 
453
1043
  require 'jose/jwk/pem'
1044
+ require 'jose/jwk/openssh_key'
454
1045
  require 'jose/jwk/set'
455
1046
  require 'jose/jwk/kty'