@@ -73,65 +73,88 @@ def import(jwk_data)
73
73
new ( rsa_pkey ( pkey_params ) , kid : jwk_attributes ( jwk_data , :kid ) [ :kid ] )
74
74
end
75
75
76
- private
76
+ RSA_OPT_PARAMS = %i[ p q dp dq qi ] . freeze
77
+ RSA_ASN1_SEQUENCE = ( %i[ n e d ] + RSA_OPT_PARAMS ) . freeze # https://www.rfc-editor.org/rfc/rfc3447#appendix-A.1.2
77
78
78
- def jwk_attributes ( jwk_data , *attributes )
79
- attributes . each_with_object ( { } ) do |attribute , hash |
80
- value = jwk_data [ attribute ] || jwk_data [ attribute . to_s ]
81
- value = yield ( value ) if block_given?
82
- hash [ attribute ] = value
79
+ def create_rsa_key_using_der ( rsa_parameters )
80
+ validate_rsa_parameters! ( rsa_parameters )
81
+
82
+ sequence = RSA_ASN1_SEQUENCE . each_with_object ( [ ] ) do |key , arr |
83
+ next if rsa_parameters [ key ] . nil?
84
+
85
+ arr << OpenSSL ::ASN1 ::Integer . new ( rsa_parameters [ key ] )
83
86
end
84
- end
85
87
86
- def rsa_pkey ( rsa_parameters )
87
- raise JWT ::JWKError , 'Key format is invalid for RSA' unless rsa_parameters [ :n ] && rsa_parameters [ :e ]
88
+ if sequence . size > 2 # Append "two-prime" version for private key
89
+ sequence . unshift ( OpenSSL ::ASN1 ::Integer . new ( 0 ) )
90
+ end
88
91
89
- create_rsa_key ( rsa_parameters )
92
+ OpenSSL :: PKey :: RSA . new ( OpenSSL :: ASN1 :: Sequence ( sequence ) . to_der )
90
93
end
91
94
92
- if ::JWT . openssl_3?
93
- ASN1_SEQUENCE = %i[ n e d p q dp dq qi ] . freeze
94
- def create_rsa_key ( rsa_parameters )
95
- sequence = ASN1_SEQUENCE . each_with_object ( [ ] ) do |key , arr |
96
- next if rsa_parameters [ key ] . nil?
95
+ def create_rsa_key_using_sets ( rsa_parameters )
96
+ validate_rsa_parameters! ( rsa_parameters )
97
97
98
- arr << OpenSSL ::ASN1 :: Integer . new ( rsa_parameters [ key ] )
99
- end
100
-
101
- if sequence . size > 2 # For a private key
102
- sequence . unshift ( OpenSSL :: ASN1 :: Integer . new ( 0 ) )
103
- end
98
+ OpenSSL ::PKey :: RSA . new . tap do | rsa_key |
99
+ rsa_key . set_key ( rsa_parameters [ :n ] , rsa_parameters [ :e ] , rsa_parameters [ :d ] )
100
+ rsa_key . set_factors ( rsa_parameters [ :p ] , rsa_parameters [ :q ] ) if rsa_parameters [ :p ] && rsa_parameters [ :q ]
101
+ rsa_key . set_crt_params ( rsa_parameters [ :dp ] , rsa_parameters [ :dq ] , rsa_parameters [ :qi ] ) if rsa_parameters [ :dp ] && rsa_parameters [ :dq ] && rsa_parameters [ :qi ]
102
+ end
103
+ end
104
104
105
- OpenSSL ::PKey ::RSA . new ( OpenSSL ::ASN1 ::Sequence ( sequence ) . to_der )
105
+ def create_rsa_key_using_accessors ( rsa_parameters ) # rubocop:disable Metrics/AbcSize
106
+ validate_rsa_parameters! ( rsa_parameters )
107
+
108
+ OpenSSL ::PKey ::RSA . new . tap do |rsa_key |
109
+ rsa_key . n = rsa_parameters [ :n ]
110
+ rsa_key . e = rsa_parameters [ :e ]
111
+ rsa_key . d = rsa_parameters [ :d ] if rsa_parameters [ :d ]
112
+ rsa_key . p = rsa_parameters [ :p ] if rsa_parameters [ :p ]
113
+ rsa_key . q = rsa_parameters [ :q ] if rsa_parameters [ :q ]
114
+ rsa_key . dmp1 = rsa_parameters [ :dp ] if rsa_parameters [ :dp ]
115
+ rsa_key . dmq1 = rsa_parameters [ :dq ] if rsa_parameters [ :dq ]
116
+ rsa_key . iqmp = rsa_parameters [ :qi ] if rsa_parameters [ :qi ]
106
117
end
118
+ end
119
+
120
+ if ::JWT . openssl_3?
121
+ alias create_rsa_key create_rsa_key_using_der
107
122
elsif OpenSSL ::PKey ::RSA . new . respond_to? ( :set_key )
108
- def create_rsa_key ( rsa_parameters )
109
- OpenSSL ::PKey ::RSA . new . tap do |rsa_key |
110
- rsa_key . set_key ( rsa_parameters [ :n ] , rsa_parameters [ :e ] , rsa_parameters [ :d ] )
111
- rsa_key . set_factors ( rsa_parameters [ :p ] , rsa_parameters [ :q ] ) if rsa_parameters [ :p ] && rsa_parameters [ :q ]
112
- rsa_key . set_crt_params ( rsa_parameters [ :dp ] , rsa_parameters [ :dq ] , rsa_parameters [ :qi ] ) if rsa_parameters [ :dp ] && rsa_parameters [ :dq ] && rsa_parameters [ :qi ]
113
- end
114
- end
123
+ alias create_rsa_key create_rsa_key_using_sets
115
124
else
116
- def create_rsa_key ( rsa_parameters ) # rubocop:disable Metrics/AbcSize
117
- OpenSSL ::PKey ::RSA . new . tap do |rsa_key |
118
- rsa_key . n = rsa_parameters [ :n ]
119
- rsa_key . e = rsa_parameters [ :e ]
120
- rsa_key . d = rsa_parameters [ :d ] if rsa_parameters [ :d ]
121
- rsa_key . p = rsa_parameters [ :p ] if rsa_parameters [ :p ]
122
- rsa_key . q = rsa_parameters [ :q ] if rsa_parameters [ :q ]
123
- rsa_key . dmp1 = rsa_parameters [ :dp ] if rsa_parameters [ :dp ]
124
- rsa_key . dmq1 = rsa_parameters [ :dq ] if rsa_parameters [ :dq ]
125
- rsa_key . iqmp = rsa_parameters [ :qi ] if rsa_parameters [ :qi ]
126
- end
127
- end
125
+ alias create_rsa_key create_rsa_key_using_accessors
128
126
end
129
127
130
128
def decode_open_ssl_bn ( jwk_data )
131
129
return nil unless jwk_data
132
130
133
131
OpenSSL ::BN . new ( ::JWT ::Base64 . url_decode ( jwk_data ) , BINARY )
134
132
end
133
+
134
+ private
135
+
136
+ def validate_rsa_parameters! ( rsa_parameters )
137
+ return unless rsa_parameters [ :d ]
138
+
139
+ return if RSA_OPT_PARAMS . all? { |k | rsa_parameters . keys . include? ( k ) }
140
+ return if RSA_OPT_PARAMS . none? { |k | rsa_parameters . keys . include? ( k ) }
141
+
142
+ raise JWT ::JWKError , 'When one of p, q, dp, dq or qi is given all the other optimization parameters also needs to be defined'
143
+ end
144
+
145
+ def jwk_attributes ( jwk_data , *attributes )
146
+ attributes . each_with_object ( { } ) do |attribute , hash |
147
+ value = jwk_data [ attribute ] || jwk_data [ attribute . to_s ]
148
+ value = yield ( value ) if block_given?
149
+ hash [ attribute ] = value
150
+ end
151
+ end
152
+
153
+ def rsa_pkey ( rsa_parameters )
154
+ raise JWT ::JWKError , 'Key format is invalid for RSA' unless rsa_parameters [ :n ] && rsa_parameters [ :e ]
155
+
156
+ create_rsa_key ( rsa_parameters )
157
+ end
135
158
end
136
159
end
137
160
end
0 commit comments