@@ -48,6 +48,14 @@ func hashToMD(h hash.Hash) ossl.EVP_MD_PTR {
4848 return nil
4949}
5050
51+ // hashToCryptoHash converts a hash.Hash implementation from this package to a crypto.Hash.
52+ func hashToCryptoHash (h hash.Hash ) crypto.Hash {
53+ if h , ok := h .(* Hash ); ok {
54+ return h .alg .ch
55+ }
56+ return 0
57+ }
58+
5159// hashFuncToMD converts a hash.Hash function to a GOossl.EVP_MD_PTR.
5260// See [hashFuncHash] for details on error handling.
5361func hashFuncToMD (fn func () hash.Hash ) (ossl.EVP_MD_PTR , error ) {
@@ -294,92 +302,104 @@ func setupEVP(withKey withKeyFunc, padding int32,
294302 }
295303 // Each padding type has its own requirements in terms of when to apply the padding,
296304 // so it can't be just set at this point.
297- setPadding := func () error {
298- _ , err := ossl .EVP_PKEY_CTX_ctrl (ctx , ossl .EVP_PKEY_RSA , - 1 , ossl .EVP_PKEY_CTRL_RSA_PADDING , padding , nil )
299- return err
300- }
301305 switch padding {
302306 case ossl .RSA_PKCS1_OAEP_PADDING :
303- md := hashToMD (h )
304- if md == nil {
305- return nil , errors .New ("crypto/rsa: unsupported hash function" )
306- }
307- var mgfMD ossl.EVP_MD_PTR
308- if mgfHash != nil {
309- // mgfHash is optional, but if it is set it must match a supported hash function.
310- mgfMD = hashToMD (mgfHash )
311- if mgfMD == nil {
312- return nil , errors .New ("crypto/rsa: unsupported hash function" )
313- }
314- }
315- // setPadding must happen before setting EVP_PKEY_CTRL_RSA_OAEP_MD.
316- if err := setPadding (); err != nil {
317- return nil , err
318- }
319- if _ , err := ossl .EVP_PKEY_CTX_ctrl (ctx , ossl .EVP_PKEY_RSA , - 1 , ossl .EVP_PKEY_CTRL_RSA_OAEP_MD , 0 , unsafe .Pointer (md )); err != nil {
320- return nil , err
321- }
322- if mgfHash != nil {
323- if _ , err := ossl .EVP_PKEY_CTX_ctrl (ctx , ossl .EVP_PKEY_RSA , - 1 , ossl .EVP_PKEY_CTRL_RSA_MGF1_MD , 0 , unsafe .Pointer (mgfMD )); err != nil {
324- return nil , err
325- }
326- }
327- // ctx takes ownership of label, so malloc a copy for OpenSSL to free.
328- // OpenSSL does not take ownership of the label if the length is zero,
329- // so better avoid the allocation.
330- var clabel * byte
331- if len (label ) > 0 {
332- clabel = (* byte )(cryptoMalloc (len (label )))
333- copy ((* [1 << 30 ]byte )(unsafe .Pointer (clabel ))[:len (label )], label )
334- var err error
335- if major () == 3 {
336- _ , err = ossl .EVP_PKEY_CTX_set0_rsa_oaep_label (ctx , unsafe .Pointer (clabel ), int32 (len (label )))
337- } else {
338- _ , err = ossl .EVP_PKEY_CTX_ctrl (ctx , ossl .EVP_PKEY_RSA , - 1 , ossl .EVP_PKEY_CTRL_RSA_OAEP_LABEL , int32 (len (label )), unsafe .Pointer (clabel ))
339- }
340- if err != nil {
341- cryptoFree (unsafe .Pointer (clabel ))
342- return nil , err
343- }
344- }
307+ err = setOAEPPadding (ctx , h , mgfHash , label )
345308 case ossl .RSA_PKCS1_PSS_PADDING :
346- alg := loadHash (ch , false )
347- if alg == nil {
348- return nil , errors .New ("crypto/rsa: unsupported hash function" )
349- }
350- if _ , err := ossl .EVP_PKEY_CTX_ctrl (ctx , ossl .EVP_PKEY_RSA , - 1 , ossl .EVP_PKEY_CTRL_MD , 0 , unsafe .Pointer (alg .md )); err != nil {
351- return nil , err
309+ err = setPSSPadding (ctx , saltLen , ch )
310+ case ossl .RSA_PKCS1_PADDING :
311+ err = setPKCS1Padding (ctx , ch )
312+ default :
313+ _ , err = ossl .EVP_PKEY_CTX_ctrl (ctx , ossl .EVP_PKEY_RSA , - 1 , ossl .EVP_PKEY_CTRL_RSA_PADDING , padding , nil )
314+ }
315+ if err != nil {
316+ return nil , err
317+ }
318+ return ctx , nil
319+ }
320+
321+ func setPSSPadding (ctx ossl.EVP_PKEY_CTX_PTR , saltLen int32 , ch crypto.Hash ) error {
322+ alg := loadHash (ch , false )
323+ if alg == nil {
324+ return errors .New ("crypto/rsa: unsupported hash function" )
325+ }
326+ if _ , err := ossl .EVP_PKEY_CTX_ctrl (ctx , ossl .EVP_PKEY_RSA , - 1 , ossl .EVP_PKEY_CTRL_MD , 0 , unsafe .Pointer (alg .md )); err != nil {
327+ return err
328+ }
329+ // setPadding must happen after setting EVP_PKEY_CTRL_MD.
330+ if _ , err := ossl .EVP_PKEY_CTX_ctrl (ctx , ossl .EVP_PKEY_RSA , - 1 , ossl .EVP_PKEY_CTRL_RSA_PADDING , ossl .RSA_PKCS1_PSS_PADDING , nil ); err != nil {
331+ return err
332+ }
333+ if saltLen != 0 {
334+ if _ , err := ossl .EVP_PKEY_CTX_ctrl (ctx , ossl .EVP_PKEY_RSA , - 1 , ossl .EVP_PKEY_CTRL_RSA_PSS_SALTLEN , saltLen , nil ); err != nil {
335+ return err
352336 }
353- // setPadding must happen after setting EVP_PKEY_CTRL_MD.
354- if err := setPadding (); err != nil {
355- return nil , err
337+ }
338+ return nil
339+ }
340+
341+ func setPKCS1Padding (ctx ossl.EVP_PKEY_CTX_PTR , ch crypto.Hash ) error {
342+ if ch == 0 {
343+ // We support unhashed messages.
344+ return nil
345+ }
346+ alg := loadHash (ch , false )
347+ if alg == nil {
348+ return errors .New ("crypto/rsa: unsupported hash function" )
349+ }
350+ if _ , err := ossl .EVP_PKEY_CTX_ctrl (ctx , - 1 , - 1 , ossl .EVP_PKEY_CTRL_MD , 0 , unsafe .Pointer (alg .md )); err != nil {
351+ return err
352+ }
353+ if _ , err := ossl .EVP_PKEY_CTX_ctrl (ctx , ossl .EVP_PKEY_RSA , - 1 , ossl .EVP_PKEY_CTRL_RSA_PADDING , ossl .RSA_PKCS1_PADDING , nil ); err != nil {
354+ return err
355+ }
356+ return nil
357+ }
358+
359+ func setOAEPPadding (ctx ossl.EVP_PKEY_CTX_PTR , h , mgfHash hash.Hash , label []byte ) error {
360+ md := hashToMD (h )
361+ if md == nil {
362+ return errors .New ("crypto/rsa: unsupported hash function" )
363+ }
364+ var mgfMD ossl.EVP_MD_PTR
365+ if mgfHash != nil {
366+ // mgfHash is optional, but if it is set it must match a supported hash function.
367+ mgfMD = hashToMD (mgfHash )
368+ if mgfMD == nil {
369+ return errors .New ("crypto/rsa: unsupported hash function" )
356370 }
357- if saltLen != 0 {
358- if _ , err := ossl .EVP_PKEY_CTX_ctrl (ctx , ossl .EVP_PKEY_RSA , - 1 , ossl .EVP_PKEY_CTRL_RSA_PSS_SALTLEN , saltLen , nil ); err != nil {
359- return nil , err
360- }
371+ }
372+ // setPadding must happen before setting EVP_PKEY_CTRL_RSA_OAEP_MD.
373+ if _ , err := ossl .EVP_PKEY_CTX_ctrl (ctx , ossl .EVP_PKEY_RSA , - 1 , ossl .EVP_PKEY_CTRL_RSA_PADDING , ossl .RSA_PKCS1_OAEP_PADDING , nil ); err != nil {
374+ return err
375+ }
376+ if _ , err := ossl .EVP_PKEY_CTX_ctrl (ctx , ossl .EVP_PKEY_RSA , - 1 , ossl .EVP_PKEY_CTRL_RSA_OAEP_MD , 0 , unsafe .Pointer (md )); err != nil {
377+ return err
378+ }
379+ if mgfHash != nil {
380+ if _ , err := ossl .EVP_PKEY_CTX_ctrl (ctx , ossl .EVP_PKEY_RSA , - 1 , ossl .EVP_PKEY_CTRL_RSA_MGF1_MD , 0 , unsafe .Pointer (mgfMD )); err != nil {
381+ return err
361382 }
362-
363- case ossl .RSA_PKCS1_PADDING :
364- if ch != 0 {
365- // We support unhashed messages.
366- alg := loadHash (ch , false )
367- if alg == nil {
368- return nil , errors .New ("crypto/rsa: unsupported hash function" )
369- }
370- if _ , err := ossl .EVP_PKEY_CTX_ctrl (ctx , - 1 , - 1 , ossl .EVP_PKEY_CTRL_MD , 0 , unsafe .Pointer (alg .md )); err != nil {
371- return nil , err
372- }
373- if err := setPadding (); err != nil {
374- return nil , err
375- }
383+ }
384+ // ctx takes ownership of label, so malloc a copy for OpenSSL to free.
385+ // OpenSSL does not take ownership of the label if the length is zero,
386+ // so better avoid the allocation.
387+ var clabel * byte
388+ if len (label ) > 0 {
389+ clabel = (* byte )(cryptoMalloc (len (label )))
390+ copy ((* [1 << 30 ]byte )(unsafe .Pointer (clabel ))[:len (label )], label )
391+ var err error
392+ if major () == 3 {
393+ _ , err = ossl .EVP_PKEY_CTX_set0_rsa_oaep_label (ctx , unsafe .Pointer (clabel ), int32 (len (label )))
394+ } else {
395+ _ , err = ossl .EVP_PKEY_CTX_ctrl (ctx , ossl .EVP_PKEY_RSA , - 1 , ossl .EVP_PKEY_CTRL_RSA_OAEP_LABEL , int32 (len (label )), unsafe .Pointer (clabel ))
376396 }
377- default :
378- if err := setPadding (); err != nil {
379- return nil , err
397+ if err != nil {
398+ cryptoFree ( unsafe . Pointer ( clabel ))
399+ return err
380400 }
381401 }
382- return ctx , nil
402+ return nil
383403}
384404
385405func cryptEVP (withKey withKeyFunc , padding int32 ,
0 commit comments