@@ -142,6 +142,7 @@ def _rsa_sig_determine_padding(backend, key, padding, algorithm):
142
142
backend .openssl_assert (pkey_size > 0 )
143
143
144
144
if isinstance (padding , PKCS1v15 ):
145
+ # Hash algorithm is ignored for PKCS1v15-padding, may be None.
145
146
padding_enum = backend ._lib .RSA_PKCS1_PADDING
146
147
elif isinstance (padding , PSS ):
147
148
if not isinstance (padding ._mgf , MGF1 ):
@@ -150,6 +151,10 @@ def _rsa_sig_determine_padding(backend, key, padding, algorithm):
150
151
_Reasons .UNSUPPORTED_MGF ,
151
152
)
152
153
154
+ # PSS padding requires a hash algorithm
155
+ if not isinstance (algorithm , hashes .HashAlgorithm ):
156
+ raise TypeError ("Expected instance of hashes.HashAlgorithm." )
157
+
153
158
# Size of key in bytes - 2 is the maximum
154
159
# PSS signature length (salt length is checked later)
155
160
if pkey_size - algorithm .digest_size - 2 < 0 :
@@ -168,25 +173,37 @@ def _rsa_sig_determine_padding(backend, key, padding, algorithm):
168
173
return padding_enum
169
174
170
175
171
- def _rsa_sig_setup (backend , padding , algorithm , key , data , init_func ):
176
+ # Hash algorithm can be absent (None) to initialize the context without setting
177
+ # any message digest algorithm. This is currently only valid for the PKCS1v15
178
+ # padding type, where it means that the signature data is encoded/decoded
179
+ # as provided, without being wrapped in a DigestInfo structure.
180
+ def _rsa_sig_setup (backend , padding , algorithm , key , init_func ):
172
181
padding_enum = _rsa_sig_determine_padding (backend , key , padding , algorithm )
173
- evp_md = backend ._evp_md_non_null_from_algorithm (algorithm )
174
182
pkey_ctx = backend ._lib .EVP_PKEY_CTX_new (key ._evp_pkey , backend ._ffi .NULL )
175
183
backend .openssl_assert (pkey_ctx != backend ._ffi .NULL )
176
184
pkey_ctx = backend ._ffi .gc (pkey_ctx , backend ._lib .EVP_PKEY_CTX_free )
177
185
res = init_func (pkey_ctx )
178
186
backend .openssl_assert (res == 1 )
179
- res = backend ._lib .EVP_PKEY_CTX_set_signature_md (pkey_ctx , evp_md )
180
- if res == 0 :
187
+ if algorithm is not None :
188
+ evp_md = backend ._evp_md_non_null_from_algorithm (algorithm )
189
+ res = backend ._lib .EVP_PKEY_CTX_set_signature_md (pkey_ctx , evp_md )
190
+ if res == 0 :
191
+ backend ._consume_errors ()
192
+ raise UnsupportedAlgorithm (
193
+ "{} is not supported by this backend for RSA signing." .format (
194
+ algorithm .name
195
+ ),
196
+ _Reasons .UNSUPPORTED_HASH ,
197
+ )
198
+ res = backend ._lib .EVP_PKEY_CTX_set_rsa_padding (pkey_ctx , padding_enum )
199
+ if res <= 0 :
181
200
backend ._consume_errors ()
182
201
raise UnsupportedAlgorithm (
183
- "{} is not supported by this backend for RSA signing ." .format (
184
- algorithm .name
202
+ "{} is not supported for the RSA signature operation ." .format (
203
+ padding .name
185
204
),
186
- _Reasons .UNSUPPORTED_HASH ,
205
+ _Reasons .UNSUPPORTED_PADDING ,
187
206
)
188
- res = backend ._lib .EVP_PKEY_CTX_set_rsa_padding (pkey_ctx , padding_enum )
189
- backend .openssl_assert (res > 0 )
190
207
if isinstance (padding , PSS ):
191
208
res = backend ._lib .EVP_PKEY_CTX_set_rsa_pss_saltlen (
192
209
pkey_ctx , _get_rsa_pss_salt_length (padding , key , algorithm )
@@ -208,7 +225,6 @@ def _rsa_sig_sign(backend, padding, algorithm, private_key, data):
208
225
padding ,
209
226
algorithm ,
210
227
private_key ,
211
- data ,
212
228
backend ._lib .EVP_PKEY_sign_init ,
213
229
)
214
230
buflen = backend ._ffi .new ("size_t *" )
@@ -235,7 +251,6 @@ def _rsa_sig_verify(backend, padding, algorithm, public_key, signature, data):
235
251
padding ,
236
252
algorithm ,
237
253
public_key ,
238
- data ,
239
254
backend ._lib .EVP_PKEY_verify_init ,
240
255
)
241
256
res = backend ._lib .EVP_PKEY_verify (
@@ -250,6 +265,36 @@ def _rsa_sig_verify(backend, padding, algorithm, public_key, signature, data):
250
265
raise InvalidSignature
251
266
252
267
268
+ def _rsa_sig_recover (backend , padding , algorithm , public_key , signature ):
269
+ pkey_ctx = _rsa_sig_setup (
270
+ backend ,
271
+ padding ,
272
+ algorithm ,
273
+ public_key ,
274
+ backend ._lib .EVP_PKEY_verify_recover_init ,
275
+ )
276
+
277
+ # Attempt to keep the rest of the code in this function as constant/time
278
+ # as possible. See the comment in _enc_dec_rsa_pkey_ctx. Note that the
279
+ # outlen parameter is used even though its value may be undefined in the
280
+ # error case. Due to the tolerant nature of Python slicing this does not
281
+ # trigger any exceptions.
282
+ maxlen = backend ._lib .EVP_PKEY_size (public_key ._evp_pkey )
283
+ backend .openssl_assert (maxlen > 0 )
284
+ buf = backend ._ffi .new ("unsigned char[]" , maxlen )
285
+ buflen = backend ._ffi .new ("size_t *" , maxlen )
286
+ res = backend ._lib .EVP_PKEY_verify_recover (
287
+ pkey_ctx , buf , buflen , signature , len (signature )
288
+ )
289
+ resbuf = backend ._ffi .buffer (buf )[: buflen [0 ]]
290
+ backend ._lib .ERR_clear_error ()
291
+ # Assume that all parameter errors are handled during the setup phase and
292
+ # any error here is due to invalid signature.
293
+ if res != 1 :
294
+ raise InvalidSignature
295
+ return resbuf
296
+
297
+
253
298
@utils .register_interface (AsymmetricSignatureContext )
254
299
class _RSASignatureContext (object ):
255
300
def __init__ (self , backend , private_key , padding , algorithm ):
@@ -463,3 +508,9 @@ def verify(self, signature, data, padding, algorithm):
463
508
return _rsa_sig_verify (
464
509
self ._backend , padding , algorithm , self , signature , data
465
510
)
511
+
512
+ def recover_data_from_signature (self , signature , padding , algorithm ):
513
+ _check_not_prehashed (algorithm )
514
+ return _rsa_sig_recover (
515
+ self ._backend , padding , algorithm , self , signature
516
+ )
0 commit comments