]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Merge topic branch t/openssl-3 into pu
authorAndre Noll <maan@tuebingen.mpg.de>
Sun, 17 Mar 2024 11:36:38 +0000 (12:36 +0100)
committerAndre Noll <maan@tuebingen.mpg.de>
Sun, 17 Mar 2024 11:36:38 +0000 (12:36 +0100)
Started on 2023-04-29.

The series starts with a few cleanups and crypto-backend tweaks to
beat the openssl specific code into shape for the main objective:
the switch of the RSA encryption and decryption routines to the
high-level EVP API. This has become necessary because the old RSA
API functions have been deprecated in openssl-3.

<!--

- The openssl RSA code has been converted to EVP and no longer uses
  any deprecated openssl API functions.

-->

* refs/heads/t/openssl-3:
  openssl: Reactivate openssl warnings.
  openssl: Use the EVP library for RSA private decryption.
  openssl: Use the EVP library for RSA public encryption.
  apc_priv_decrypt: Let the callee allocate the buffer.
  apc_pub_encrypt: Let the callee allocate the buffer.
  openssl: Assume that openssl allocation functions functions succeed.
  openssl: Introduce openssl_perror().
  openssl: Don't pass pointers to RSA structures around.
  openssl: Kill rsa coefficient computations.
  client: Check buffer size returned by apc_priv_decrypt().

# Conflicts:
# configure.ac

1  2 
Makefile.real
configure.ac
openssl.c

diff --combined Makefile.real
index 92a5724b3cc6543553dcaf8dbdf6385e4169e41e,d348ee1410fe3cb9611fd19ac1f865184911440b..21d5fc03477145f087be31a319838d636d3df2b2
@@@ -14,6 -14,7 +14,6 @@@ SEVERITIES := \"debug\",\"info\",\"noti
  vardir := /var/paraslash
  mandir := $(datarootdir)/man/man1
  MKDIR_P := mkdir -p
 -prefixed_executables := $(addprefix para_, $(executables))
  
  build_date := $(shell date)
  uname_s := $(shell uname -s 2>/dev/null || echo "UNKNOWN_OS")
@@@ -34,263 -35,15 +34,263 @@@ m4depdir := $(build_dir)/m4dep
  lls_suite_dir := $(build_dir)/lls
  lls_m4_dir := m4/lls
  test_dir := t
 -yy_src_dir = yy
 -yy_build_dir = $(build_dir)/yy
 +yy_src_dir := yy
 +yy_build_dir := $(build_dir)/yy
 +
 +executables := recv filter audioc write afh play
 +ifneq ($(CRYPTOLIB),)
 +      ifeq ($(HAVE_OSL),yes)
 +      executables += server upgrade_db
 +              server_objs := $(addsuffix .o, \
 +                      server afh_common mp3_afh vss command net string \
 +                      signal time daemon http_send close_on_fork \
 +                      crypt_common base64 ipc dccp_send fd user_list \
 +                      chunk_queue afs aft mood mp score attribute blob \
 +                      playlist sched acl send_common udp_send color fec \
 +                      wma_afh wma_common sideband version lsu \
 +              )
 +              ifeq ($(CRYPTOLIB),openssl)
 +                      server_objs += openssl.o
 +              else
 +                      server_objs += gcrypt.o
 +              endif
 +              ifeq ($(NEED_OGG_OBJECTS),yes)
 +                      server_objs += ogg_afh_common.o
 +              endif
 +              ifeq ($(NEED_VORBIS_OBJECTS),yes)
 +                      server_objs += ogg_afh.o
 +              endif
 +              ifeq ($(NEED_SPEEX_OBJECTS),yes)
 +                      server_objs += spx_afh.o spx_common.o
 +              endif
 +              ifeq ($(NEED_OPUS_OBJECTS),yes)
 +                      server_objs += opus_afh.o opus_common.o
 +              endif
 +              ifeq ($(NEED_FLAC_OBJECTS),yes)
 +                      server_objs += flac_afh.o
 +              endif
 +              ifeq ($(HAVE_FAAD),yes)
 +                      server_objs += aac_afh.o mp4.o
 +              endif
 +              upgrade_db_objs := $(addsuffix .o, crypt_common exec fd string \
 +                      upgrade_db version base64)
 +      endif
 +endif
 +ifneq ($(CRYPTOLIB),)
 +      executables += client audiod
 +      client_objs := $(addsuffix .o, \
 +              client net string fd lsu sched stdin stdout time sideband client_common \
 +              buffer_tree crypt_common base64 version $(CRYPTOLIB) \
 +      )
 +      ifeq ($(HAVE_READLINE),yes)
 +              client_objs += interactive.o
 +      endif
 +      audiod_objs := $(addsuffix .o, \
 +              audiod signal string daemon stat net crypt_common base64 sideband \
 +              time grab_client filter_common wav_filter compress_filter amp_filter \
 +              http_recv dccp_recv recv_common fd sched write_common file_write \
 +              audiod_command fecdec_filter client_common udp_recv color fec \
 +              prebuffer_filter version bitstream imdct wma_common wmadec_filter \
 +              buffer_tree sync_filter lsu $(CRYPTOLIB) \
 +      )
 +      audiod_audio_formats := "wma"
 +      ifeq ($(NEED_VORBIS_OBJECTS),yes)
 +              audiod_objs += oggdec_filter.o
 +              audiod_audio_formats += ,"ogg"
 +      endif
 +      ifeq ($(NEED_SPEEX_OBJECTS),yes)
 +              audiod_objs += spxdec_filter.o spx_common.o
 +              audiod_audio_formats += ,"spx"
 +      endif
 +      ifeq ($(NEED_OPUS_OBJECTS),yes)
 +              audiod_objs += opusdec_filter.o opus_common.o
 +              audiod_audio_formats += ,"opus"
 +      endif
 +      ifeq ($(NEED_FLAC_OBJECTS),yes)
 +              audiod_objs += flacdec_filter.o
 +              audiod_audio_formats += ,"flac"
 +      endif
 +      ifeq ($(HAVE_FAAD),yes)
 +              audiod_objs += aacdec_filter.o
 +              audiod_audio_formats += ,"aac"
 +      endif
 +      ifeq ($(HAVE_MAD),yes)
 +              audiod_objs += mp3dec_filter.o
 +              audiod_audio_formats += ,"mp3"
 +      endif
 +      ifeq ($(HAVE_OSS),yes)
 +              audiod_objs += oss_write.o
 +      endif
 +      ifeq ($(HAVE_ALSA),yes)
 +              audiod_objs += alsa_write.o
 +      endif
 +      ifeq ($(NEED_AO_OBJECTS),yes)
 +              audiod_objs += ao_write.o
 +      endif
 +      ifeq ($(HAVE_SAMPLERATE),yes)
 +              audiod_objs += resample_filter.o check_wav.o
 +      endif
 +endif
 +ifneq ($(HAVE_OSS)-$(HAVE_ALSA),no-no)
 +      executables += mixer
 +      mixer_objs := $(addsuffix .o, mixer exec string fd time lsu version)
 +      ifeq ($(HAVE_OSS),yes)
 +              mixer_objs += oss_mix.o
 +      endif
 +      ifeq ($(HAVE_ALSA),yes)
 +              mixer_objs += alsa_mix.o
 +      endif
 +endif
 +ifeq ($(HAVE_CURSES),yes)
 +      executables += gui
 +      gui_objs := $(addsuffix .o, exec signal string stat ringbuffer fd \
 +              gui gui_theme lsu time sched version)
 +endif
 +filter_objs := $(addsuffix .o, \
 +      filter_common wav_filter compress_filter filter string stdin stdout \
 +      sched fd amp_filter fecdec_filter fec lsu version prebuffer_filter \
 +      time bitstream imdct wma_common wmadec_filter buffer_tree net \
 +      sync_filter \
 +)
 +ifeq ($(NEED_VORBIS_OBJECTS),yes)
 +      filter_objs += oggdec_filter.o
 +endif
 +ifeq ($(NEED_SPEEX_OBJECTS),yes)
 +      filter_objs += spxdec_filter.o spx_common.o
 +endif
 +ifeq ($(NEED_OPUS_OBJECTS),yes)
 +      filter_objs += opusdec_filter.o opus_common.o
 +endif
 +ifeq ($(NEED_FLAC_OBJECTS),yes)
 +      filter_objs += flacdec_filter.o
 +endif
 +ifeq ($(HAVE_FAAD),yes)
 +      filter_objs += aacdec_filter.o
 +endif
 +ifeq ($(HAVE_MAD),yes)
 +      filter_objs += mp3dec_filter.o
 +endif
 +ifeq ($(HAVE_SAMPLERATE),yes)
 +      filter_objs += resample_filter.o check_wav.o
 +endif
 +
 +recv_objs := $(addsuffix .o, \
 +      http_recv recv_common recv time string net dccp_recv fd sched stdout \
 +      udp_recv buffer_tree afh_recv afh_common wma_afh wma_common mp3_afh \
 +      version \
 +)
 +ifeq ($(NEED_OGG_OBJECTS),yes)
 +      recv_objs += ogg_afh_common.o
 +endif
 +ifeq ($(NEED_VORBIS_OBJECTS),yes)
 +      recv_objs += ogg_afh.o
 +endif
 +ifeq ($(NEED_SPEEX_OBJECTS),yes)
 +      recv_objs += spx_afh.o spx_common.o
 +endif
 +ifeq ($(NEED_OPUS_OBJECTS),yes)
 +      recv_objs += opus_afh.o opus_common.o
 +endif
 +ifeq ($(NEED_FLAC_OBJECTS),yes)
 +      recv_objs += flac_afh.o
 +endif
 +ifeq ($(HAVE_FAAD),yes)
 +      recv_objs += aac_afh.o mp4.o
 +endif
 +
 +audio_format_handlers := mp3 wma
 +afh_objs := $(addsuffix .o, afh string fd mp3_afh afh_common time wma_afh \
 +      wma_common version)
 +ifeq ($(NEED_OGG_OBJECTS),yes)
 +      afh_objs += ogg_afh_common.o
 +endif
 +ifeq ($(NEED_VORBIS_OBJECTS),yes)
 +      afh_objs += ogg_afh.o
 +      audio_format_handlers += ogg
 +endif
 +ifeq ($(NEED_SPEEX_OBJECTS),yes)
 +      afh_objs += spx_common.o
 +      audio_format_handlers += spx
 +endif
 +ifeq ($(NEED_OPUS_OBJECTS),yes)
 +      afh_objs += opus_afh.o opus_common.o
 +      audio_format_handlers += opus
 +endif
 +ifeq ($(NEED_FLAC_OBJECTS),yes)
 +      afh_objs += flac_afh.o
 +      audio_format_handlers += flac
 +endif
 +ifeq ($(HAVE_FAAD),yes)
 +      afh_objs += aac_afh.o mp4.o
 +      audio_format_handlers += aac
 +endif
 +
 +play_objs := $(addsuffix .o, \
 +      play fd sched buffer_tree time string net afh_recv afh_common \
 +      wma_afh wma_common mp3_afh recv_common udp_recv http_recv dccp_recv \
 +      filter_common fec bitstream imdct wav_filter compress_filter \
 +      amp_filter prebuffer_filter fecdec_filter wmadec_filter write_common \
 +      file_write version sync_filter lsu \
 +)
 +ifeq ($(NEED_OGG_OBJECTS),yes)
 +      play_objs += ogg_afh_common.o
 +endif
 +ifeq ($(NEED_VORBIS_OBJECTS),yes)
 +      play_objs += oggdec_filter.o ogg_afh.o
 +endif
 +ifeq ($(NEED_SPEEX_OBJECTS),yes)
 +      play_objs += spxdec_filter.o spx_afh.o spx_common.o
 +endif
 +ifeq ($(NEED_OPUS_OBJECTS),yes)
 +      play_objs += opusdec_filter.o opus_afh.o opus_common.o
 +endif
 +ifeq ($(NEED_FLAC_OBJECTS),yes)
 +      play_objs += flacdec_filter.o flac_afh.o
 +endif
 +ifeq ($(HAVE_FAAD),yes)
 +      play_objs += aac_afh.o aacdec_filter.o mp4.o
 +endif
 +ifeq ($(HAVE_MAD),yes)
 +      play_objs += mp3dec_filter.o
 +endif
 +ifeq ($(HAVE_OSS),yes)
 +      play_objs += oss_write.o
 +endif
 +ifeq ($(HAVE_ALSA),yes)
 +      play_objs += alsa_write.o
 +endif
 +ifeq ($(NEED_AO_OBJECTS),yes)
 +      play_objs += ao_write.o
 +endif
 +ifeq ($(HAVE_READLINE),yes)
 +      play_objs += interactive.o
 +endif
 +ifeq ($(HAVE_SAMPLERATE),yes)
 +      play_objs += resample_filter.o check_wav.o
 +endif
 +
 +write_objs := $(addsuffix .o, write write_common file_write time fd \
 +      string sched stdin buffer_tree check_wav version)
 +ifeq ($(NEED_AO_OBJECTS),yes)
 +      write_objs += ao_write.o
 +endif
 +ifeq ($(HAVE_OSS),yes)
 +      write_objs += oss_write.o
 +endif
 +ifeq ($(HAVE_ALSA),yes)
 +      write_objs += alsa_write.o
 +endif
 +
 +audioc_objs := $(addsuffix .o, audioc string lsu net fd time version)
 +ifeq ($(HAVE_READLINE),yes)
 +      audioc_objs += buffer_tree.o interactive.o sched.o
 +endif
  
  # sort removes duplicate words, which is all we need here
 -all_objs := $(sort $(recv_objs) $(filter_objs) $(client_objs) $(gui_objs) \
 +dep_objs := $(sort $(recv_objs) $(filter_objs) $(client_objs) $(gui_objs) \
        $(audiod_objs) $(audioc_objs) $(mixer_objs) $(server_objs) \
 -      $(write_objs) $(afh_objs) $(play_objs))
 -deps := $(addprefix $(dep_dir)/, $(all_objs:.o=.d))
 -deps += $(addprefix $(dep_dir)/, mp.bison.d mp.flex.d)
 +      $(write_objs) $(afh_objs) $(play_objs) mp.bison mp.flex)
 +deps := $(addprefix $(dep_dir)/, $(dep_objs:.o=.d))
  
  afh_objs += afh.lsg.o
  audioc_objs += audioc.lsg.o
@@@ -331,7 -84,6 +331,7 @@@ write_objs := $(addprefix $(object_dir)
  afh_objs := $(addprefix $(object_dir)/, $(afh_objs))
  play_objs := $(addprefix $(object_dir)/, $(play_objs))
  
 +prefixed_executables := $(addprefix para_, $(executables))
  man_pages := $(patsubst %, $(man_dir)/%.1, $(prefixed_executables))
  
  autocrap := config.h.in configure
@@@ -448,10 -200,6 +448,10 @@@ $(object_dir)/%.o: %.c | $(object_dir
  OD = $(addsuffix .d, $(addprefix $(dep_dir)/, $(1))) \
        $(addsuffix .o, $(addprefix $(object_dir)/, $(1)))
  
 +$(call OD, audiod): \
 +      CPPFLAGS += -DAUDIOD_AUDIO_FORMAT_ARRAY='$(audiod_audio_formats)'
 +$(call OD, afh command): \
 +      CPPFLAGS += -DAUDIO_FORMAT_HANDLERS='"$(audio_format_handlers)"'
  $(call OD, opus%): CPPFLAGS += $(opus_cppflags)
  $(call OD, gui gui%): CPPFLAGS += $(curses_cppflags)
  $(call OD, spx%): CPPFLAGS += $(speex_cppflags)
@@@ -475,7 -223,6 +475,6 @@@ $(call OD, afs aft attribute blob mood 
        CPPFLAGS += $(osl_cppflags)
  
  $(call OD, compress_filter): CFLAGS += -O3
- $(call OD, openssl): CFLAGS += -Wno-deprecated-declarations
  
  $(object_dir)/%.o: %.c | $(object_dir) $(dep_dir) $(lsg_h) $(yy_h)
  define CC_CMD
diff --combined configure.ac
index 34dcd060a5891a07dc6ea8c62ca53a7209f2a376,6a10b2960716e64592467cdf855c9f9f25f40d9e..2bba8129b92a834a998a1aea84fee9b475e3cdde
@@@ -5,6 -5,7 +5,6 @@@ AC_INIT([paraslash], [m4_esyscmd_s(./GI
  AC_CONFIG_HEADERS([config.h])
  
  AC_CONFIG_FILES([Makefile])
 -AC_DEFUN([add_dot_o],[$(for i in $@; do printf "$i.o "; done)])
  AC_DEFUN([LIB_ARG_WITH], [
        AC_ARG_WITH($1-headers, [AS_HELP_STRING(--with-$1-headers=dir,
                [look for $1 headers in dir])])
@@@ -37,7 -38,6 +37,7 @@@ AC_DEFUN([LIB_SUBST_FLAGS], 
        if test "$HAVE_[]m4_toupper([$1])" = 'yes'; then
                AC_DEFINE(HAVE_[]m4_toupper([$1]), 1,
                        define to 1 to turn on $1 support)
 +              AC_SUBST(HAVE_[]m4_toupper([$1]))
        else
                $1_cppflags=
                $1_ldflags=
@@@ -61,6 -61,7 +61,6 @@@ REQUIRE_EXECUTABLE([bison]
  REQUIRE_EXECUTABLE([flex])
  REQUIRE_EXECUTABLE([m4])
  
 -executables="recv filter audioc write afh play"
  ########################################################################### osl
  STASH_FLAGS
  LIB_ARG_WITH([osl], [-losl])
@@@ -109,6 -110,20 +109,10 @@@ if test $HAVE_OPENSSL = yes; the
        will be removed in the next major paraslash release. Please upgrade
        your openssl installation.])
        fi
 -
+       AC_CHECK_LIB([crypto], [OSSL_PARAM_construct_BN], [HAVE_OSSL_PARAM=yes],
+               [HAVE_OSSL_PARAM=no])
+       test $HAVE_OSSL_PARAM = yes &&
+               AC_DEFINE([HAVE_OSSL_PARAM], [1], [openssl >= 3.0])
 -      HAVE_CRYPTO_CLEANUP_ALL_EX_DATA=yes
 -      AC_CHECK_DECL([CRYPTO_cleanup_all_ex_data], [],
 -              [HAVE_CRYPTO_CLEANUP_ALL_EX_DATA=no],
 -              [#include <openssl/rsa.h>])
 -      AC_CHECK_LIB([crypto], [CRYPTO_cleanup_all_ex_data], [],
 -              [HAVE_CRYPTO_CLEANUP_ALL_EX_DATA=no])
 -      test $HAVE_CRYPTO_CLEANUP_ALL_EX_DATA = yes &&
 -              AC_DEFINE([HAVE_CRYPTO_CLEANUP_ALL_EX_DATA], [1],
 -                      [not available on FreeBSD 12])
        HAVE_OPENSSL_THREAD_STOP=yes
        AC_CHECK_DECL([OPENSSL_thread_stop], [],
                [HAVE_OPENSSL_THREAD_STOP=no],
@@@ -162,7 -177,6 +166,7 @@@ case "$enable_cryptolib" i
        ;;
  esac
  AC_SUBST(crypto_ldflags)
 +AC_SUBST(CRYPTOLIB)
  ########################################################################## iconv
  STASH_FLAGS
  LIBS=
@@@ -264,26 -278,27 +268,26 @@@ AC_CHECK_LIB([FLAC], [FLAC__stream_deco
  LIB_SUBST_FLAGS(flac)
  UNSTASH_FLAGS
  
 -# some helper functions for codecs which use the ogg container format
 -AC_DEFUN([NEED_OGG_OBJECTS], [{
 -      test "$HAVE_OGG" = 'yes' -a \( \
 +# some helpers for the ogg container format
 +AS_IF([test "$HAVE_OGG" = 'yes' -a \( \
                 "$HAVE_VORBIS" = 'yes' \
                -o "$HAVE_SPEEX" = 'yes' \
                -o "$HAVE_OPUS" = 'yes' \
                -o "$HAVE_FLAC" = 'yes' \
 -      \)
 -}])
 -AC_DEFUN([NEED_VORBIS_OBJECTS], [{
 -      test "$HAVE_OGG" = 'yes' -a "$HAVE_VORBIS" = 'yes'
 -}])
 -AC_DEFUN([NEED_SPEEX_OBJECTS], [{
 -      test "$HAVE_OGG" = 'yes' -a "$HAVE_SPEEX" = 'yes'
 -}])
 -AC_DEFUN([NEED_OPUS_OBJECTS], [{
 -      test "$HAVE_OGG" = 'yes' -a "$HAVE_OPUS" = 'yes'
 -}])
 -AC_DEFUN([NEED_FLAC_OBJECTS], [{
 -      test "$HAVE_OGG" = 'yes' -a "$HAVE_FLAC" = 'yes'
 -}])
 +\)], [NEED_OGG_OBJECTS=yes], [NEED_OGG_OBJECTS=no])
 +AC_SUBST([NEED_OGG_OBJECTS])
 +AS_IF([test "$HAVE_OGG" = 'yes' -a "$HAVE_VORBIS" = 'yes'],
 +      [NEED_VORBIS_OBJECTS=yes], [NEED_VORBIS_OBJECTS=no])
 +AC_SUBST([NEED_VORBIS_OBJECTS])
 +AS_IF([test "$HAVE_OGG" = 'yes' -a "$HAVE_SPEEX" = 'yes'],
 +      [NEED_SPEEX_OBJECTS=yes], [NEED_SPEEX_OBJECTS=no])
 +AC_SUBST([NEED_SPEEX_OBJECTS])
 +AS_IF([test "$HAVE_OGG" = 'yes' -a "$HAVE_OPUS" = 'yes'],
 +      [NEED_OPUS_OBJECTS=yes], [NEED_OPUS_OBJECTS=no])
 +AC_SUBST([NEED_OPUS_OBJECTS])
 +AS_IF([test "$HAVE_OGG" = 'yes' -a "$HAVE_FLAC" = 'yes'],
 +      [NEED_FLAC_OBJECTS=yes], [NEED_FLAC_OBJECTS=no])
 +AC_SUBST([NEED_FLAC_OBJECTS])
  ########################################################################### faad
  STASH_FLAGS
  LIB_ARG_WITH([faad], [-lfaad])
@@@ -339,9 -354,7 +343,9 @@@ AC_CHECK_HEADER(ao/ao.h, [], HAVE_AO=no
  AC_CHECK_LIB([ao], [ao_initialize], [], HAVE_AO=no)
  LIB_SUBST_FLAGS(ao)
  UNSTASH_FLAGS
 -AC_DEFUN([NEED_AO_OBJECTS], [{ test $HAVE_AO = yes -a $HAVE_PTHREAD = yes; }])
 +AS_IF([test $HAVE_AO = yes -a $HAVE_PTHREAD = yes],
 +      [NEED_AO_OBJECTS]=yes, [NEED_AO_OBJECTS=no])
 +AC_SUBST([NEED_AO_OBJECTS])
  ######################################################################## readline
  STASH_FLAGS
  AC_SEARCH_LIBS([tgetent], [tinfo curses terminfo termcap])
@@@ -373,5 -386,502 +377,5 @@@ AC_ARG_ENABLE([ubsan], [AS_HELP_STRING(
        [Detect and report undefined behaviour.])],
        [ENABLE_UBSAN=yes], [ENABLE_UBSAN=no])
  AC_SUBST(ENABLE_UBSAN)
 -######################################################################### server
 -if test -n "$CRYPTOLIB" && test $HAVE_OSL = yes && test -n "$BISON" && \
 -              test -n "$FLEX"; then
 -      build_server="yes"
 -      executables="$executables server upgrade_db"
 -      server_errlist_objs="
 -              server
 -              afh_common
 -              mp3_afh
 -              vss
 -              command
 -              net
 -              string
 -              signal
 -              time
 -              daemon
 -              http_send
 -              close_on_fork
 -              crypt_common
 -              base64
 -              ipc
 -              dccp_send
 -              fd
 -              user_list
 -              chunk_queue
 -              afs
 -              aft
 -              mood
 -              mp
 -              score
 -              attribute
 -              blob
 -              playlist
 -              sched
 -              acl
 -              send_common
 -              udp_send
 -              color
 -              fec
 -              wma_afh
 -              wma_common
 -              sideband
 -              version
 -              lsu
 -      "
 -      if test "$CRYPTOLIB" = openssl; then
 -              server_errlist_objs="$server_errlist_objs openssl"
 -      else
 -              server_errlist_objs="$server_errlist_objs gcrypt"
 -      fi
 -      NEED_OGG_OBJECTS() && server_errlist_objs="$server_errlist_objs ogg_afh_common"
 -      NEED_VORBIS_OBJECTS() && server_errlist_objs="$server_errlist_objs ogg_afh"
 -      NEED_SPEEX_OBJECTS() && server_errlist_objs="$server_errlist_objs spx_afh spx_common"
 -      NEED_OPUS_OBJECTS() && server_errlist_objs="$server_errlist_objs opus_afh opus_common"
 -      NEED_FLAC_OBJECTS && server_errlist_objs="$server_errlist_objs flac_afh"
 -      if test $HAVE_FAAD = yes; then
 -              server_errlist_objs="$server_errlist_objs aac_afh mp4"
 -      fi
 -      server_objs="$server_errlist_objs"
 -      AC_SUBST(server_objs, add_dot_o($server_objs))
 -else
 -      build_server="no"
 -fi
 -############################################################# upgrade_db
 -upgrade_db_objs='
 -      crypt_common
 -      exec
 -      fd
 -      string
 -      upgrade_db
 -      version
 -      base64
 -'
 -AC_SUBST(upgrade_db_objs, add_dot_o($upgrade_db_objs))
 -############################################################# client
 -if test -n "$CRYPTOLIB"; then
 -      build_client="yes"
 -      executables="$executables client"
 -      client_errlist_objs="
 -              client
 -              net
 -              string
 -              fd
 -              lsu
 -              sched
 -              stdin
 -              stdout
 -              time
 -              sideband
 -              client_common
 -              buffer_tree
 -              crypt_common
 -              base64
 -              version
 -      "
 -      if test "$CRYPTOLIB" = openssl; then
 -              client_errlist_objs="$client_errlist_objs openssl"
 -      else
 -              client_errlist_objs="$client_errlist_objs gcrypt"
 -      fi
 -      if test $HAVE_READLINE = yes; then
 -              client_errlist_objs="$client_errlist_objs interactive"
 -      fi
 -      client_objs="$client_errlist_objs"
 -      AC_SUBST(client_objs, add_dot_o($client_errlist_objs))
 -else
 -      build_client="no"
 -fi
 -############################################################# audiod
 -if test -n "$CRYPTOLIB"; then
 -      build_audiod="yes"
 -      executables="$executables audiod"
 -      audiod_audio_formats="wma"
 -      audiod_errlist_objs="$audiod_errlist_objs
 -              audiod
 -              signal
 -              string
 -              daemon
 -              stat
 -              net
 -              crypt_common
 -              base64
 -              sideband
 -              time
 -              grab_client
 -              filter_common
 -              wav_filter
 -              compress_filter
 -              amp_filter
 -              http_recv
 -              dccp_recv
 -              recv_common
 -              fd
 -              sched
 -              write_common
 -              file_write
 -              audiod_command
 -              fecdec_filter
 -              client_common
 -              udp_recv
 -              color
 -              fec
 -              prebuffer_filter
 -              version
 -              bitstream
 -              imdct
 -              wma_common
 -              wmadec_filter
 -              buffer_tree
 -              sync_filter
 -              lsu
 -      "
 -      if test "$CRYPTOLIB" = openssl; then
 -              audiod_errlist_objs="$audiod_errlist_objs openssl"
 -      else
 -              audiod_errlist_objs="$audiod_errlist_objs gcrypt"
 -      fi
 -      NEED_VORBIS_OBJECTS && {
 -              audiod_errlist_objs="$audiod_errlist_objs oggdec_filter"
 -              audiod_audio_formats="$audiod_audio_formats ogg"
 -      }
 -      NEED_SPEEX_OBJECTS && {
 -              audiod_errlist_objs="$audiod_errlist_objs spxdec_filter spx_common"
 -              audiod_audio_formats="$audiod_audio_formats spx"
 -      }
 -      NEED_OPUS_OBJECTS && {
 -              audiod_errlist_objs="$audiod_errlist_objs opusdec_filter opus_common"
 -              audiod_audio_formats="$audiod_audio_formats opus"
 -      }
 -      NEED_FLAC_OBJECTS && {
 -              audiod_errlist_objs="$audiod_errlist_objs flacdec_filter"
 -              audiod_audio_formats="$audiod_audio_formats flac"
 -      }
 -      if test $HAVE_FAAD = yes; then
 -              audiod_errlist_objs="$audiod_errlist_objs aacdec_filter"
 -              audiod_audio_formats="$audiod_audio_formats aac"
 -      fi
 -      if test $HAVE_MAD = yes; then
 -              audiod_audio_formats="$audiod_audio_formats mp3"
 -              audiod_errlist_objs="$audiod_errlist_objs mp3dec_filter"
 -      fi
 -      if test $HAVE_OSS = yes; then
 -              audiod_errlist_objs="$audiod_errlist_objs oss_write"
 -      fi
 -      if test $HAVE_ALSA = yes; then
 -              audiod_errlist_objs="$audiod_errlist_objs alsa_write"
 -      fi
 -      NEED_AO_OBJECTS && {
 -              audiod_errlist_objs="$audiod_errlist_objs ao_write"
 -      }
 -      if test $HAVE_SAMPLERATE = yes; then
 -              audiod_errlist_objs="$audiod_errlist_objs resample_filter check_wav"
 -      fi
 -      audiod_objs="$audiod_errlist_objs"
 -      AC_SUBST(audiod_objs, add_dot_o($audiod_objs))
 -
 -      enum="$(for i in $audiod_audio_formats; do printf "AUDIO_FORMAT_${i}, " | tr '[a-z]' '[A-Z]'; done)"
 -      AC_DEFINE_UNQUOTED(AUDIOD_AUDIO_FORMATS_ENUM, $enum NUM_AUDIO_FORMATS,
 -              enum of audio formats supported by audiod)
 -      names="$(for i in $audiod_audio_formats; do printf \"$i\",' ' ; done)"
 -      AC_DEFINE_UNQUOTED(AUDIOD_AUDIO_FORMAT_ARRAY, $names, array of audio formats supported by audiod)
 -else
 -      build_audiod="no"
 -fi
 -########################################################################### mixer
 -if test $HAVE_OSS = yes -o $HAVE_ALSA = yes; then
 -      build_mixer="yes"
 -      executables="$executables mixer"
 -      mixer_errlist_objs="mixer exec string fd time lsu version"
 -      if test $HAVE_OSS = yes; then
 -              mixer_errlist_objs="$mixer_errlist_objs oss_mix"
 -      fi
 -      if test $HAVE_ALSA = yes; then
 -              mixer_errlist_objs="$mixer_errlist_objs alsa_mix"
 -      fi
 -      mixer_objs="$mixer_errlist_objs"
 -      AC_SUBST(mixer_objs, add_dot_o($mixer_objs))
 -else
 -      build_mixer="no"
 -      AC_MSG_WARN([no mixer support])
 -fi
 -########################################################################### gui
 -if test $HAVE_CURSES = yes; then
 -      build_gui="yes"
 -      executables="$executables gui"
 -      gui_errlist_objs="
 -              exec
 -              signal
 -              string
 -              stat
 -              ringbuffer
 -              fd
 -              gui
 -              gui_theme
 -              lsu
 -              time
 -              sched
 -              version
 -      "
 -      gui_objs="$gui_errlist_objs"
 -      AC_SUBST(gui_objs, add_dot_o($gui_objs))
 -else
 -      build_gui="no"
 -      AC_MSG_WARN([no curses lib, cannot build para_gui])
 -fi
 -######################################################################## filter
 -filter_errlist_objs="
 -      filter_common
 -      wav_filter
 -      compress_filter
 -      filter
 -      string
 -      stdin
 -      stdout
 -      sched
 -      fd
 -      amp_filter
 -      fecdec_filter
 -      fec
 -      lsu
 -      version
 -      prebuffer_filter
 -      time
 -      bitstream
 -      imdct
 -      wma_common
 -      wmadec_filter
 -      buffer_tree
 -      net
 -      sync_filter
 -"
 -NEED_VORBIS_OBJECTS && filter_errlist_objs="$filter_errlist_objs oggdec_filter"
 -NEED_SPEEX_OBJECTS && filter_errlist_objs="$filter_errlist_objs spxdec_filter spx_common"
 -NEED_OPUS_OBJECTS && filter_errlist_objs="$filter_errlist_objs opusdec_filter opus_common"
 -NEED_FLAC_OBJECTS && filter_errlist_objs="$filter_errlist_objs flacdec_filter"
 -if test $HAVE_FAAD = yes; then
 -      filter_errlist_objs="$filter_errlist_objs aacdec_filter"
 -fi
 -if test $HAVE_MAD = yes; then
 -      filter_errlist_objs="$filter_errlist_objs mp3dec_filter"
 -fi
 -if test $HAVE_SAMPLERATE = yes; then
 -      filter_errlist_objs="$filter_errlist_objs resample_filter check_wav"
 -fi
 -filter_objs="$filter_errlist_objs"
 -
 -AC_SUBST(filter_objs, add_dot_o($filter_objs))
 -########################################################################## recv
 -recv_errlist_objs="
 -      http_recv
 -      recv_common
 -      recv
 -      time
 -      string
 -      net
 -      dccp_recv
 -      fd
 -      sched
 -      stdout
 -      udp_recv
 -      buffer_tree
 -      afh_recv
 -      afh_common
 -      wma_afh
 -      wma_common
 -      mp3_afh
 -      version
 -"
 -NEED_OGG_OBJECTS && recv_errlist_objs="$recv_errlist_objs ogg_afh_common"
 -NEED_VORBIS_OBJECTS && recv_errlist_objs="$recv_errlist_objs ogg_afh"
 -NEED_SPEEX_OBJECTS && recv_errlist_objs="$recv_errlist_objs spx_afh spx_common"
 -NEED_OPUS_OBJECTS && recv_errlist_objs="$recv_errlist_objs opus_afh opus_common"
 -NEED_FLAC_OBJECTS && recv_errlist_objs="$recv_errlist_objs flac_afh"
 -
 -if test $HAVE_FAAD = yes; then
 -      recv_errlist_objs="$recv_errlist_objs aac_afh mp4"
 -fi
 -recv_objs="$recv_errlist_objs"
 -AC_SUBST(recv_objs, add_dot_o($recv_objs))
 -########################################################################### afh
 -audio_format_handlers="mp3 wma"
 -afh_errlist_objs="
 -      afh
 -      string
 -      fd
 -      mp3_afh
 -      afh_common
 -      time
 -      wma_afh
 -      wma_common
 -      version
 -"
 -NEED_OGG_OBJECTS && afh_errlist_objs="$afh_errlist_objs ogg_afh_common"
 -NEED_VORBIS_OBJECTS && {
 -      afh_errlist_objs="$afh_errlist_objs ogg_afh"
 -      audio_format_handlers="$audio_format_handlers ogg"
 -}
 -NEED_SPEEX_OBJECTS && {
 -      afh_errlist_objs="$afh_errlist_objs spx_afh spx_common"
 -      audio_format_handlers="$audio_format_handlers spx"
 -}
 -NEED_OPUS_OBJECTS && {
 -      afh_errlist_objs="$afh_errlist_objs opus_afh opus_common"
 -      audio_format_handlers="$audio_format_handlers opus"
 -}
 -NEED_FLAC_OBJECTS && {
 -      afh_errlist_objs="$afh_errlist_objs flac_afh"
 -      audio_format_handlers="$audio_format_handlers flac"
 -}
 -if test $HAVE_FAAD = yes; then
 -      afh_errlist_objs="$afh_errlist_objs aac_afh mp4"
 -      audio_format_handlers="$audio_format_handlers aac"
 -fi
 -
 -afh_objs="$afh_errlist_objs"
 -
 -AC_SUBST(afh_objs, add_dot_o($afh_objs))
 -########################################################################## play
 -play_errlist_objs="
 -      play
 -      fd
 -      sched
 -      buffer_tree
 -      time
 -      string
 -      net
 -      afh_recv
 -      afh_common
 -      wma_afh
 -      wma_common
 -      mp3_afh
 -      recv_common
 -      udp_recv
 -      http_recv
 -      dccp_recv
 -      filter_common
 -      fec
 -      bitstream
 -      imdct
 -      wav_filter
 -      compress_filter
 -      amp_filter
 -      prebuffer_filter
 -      fecdec_filter
 -      wmadec_filter
 -      write_common
 -      file_write
 -      version
 -      sync_filter
 -      lsu
 -"
 -NEED_OGG_OBJECTS && play_errlist_objs="$play_errlist_objs ogg_afh_common"
 -NEED_VORBIS_OBJECTS && {
 -      play_errlist_objs="$play_errlist_objs oggdec_filter ogg_afh"
 -}
 -NEED_SPEEX_OBJECTS && {
 -      play_errlist_objs="$play_errlist_objs spxdec_filter spx_afh spx_common"
 -}
 -NEED_OPUS_OBJECTS &&
 -      play_errlist_objs="$play_errlist_objs
 -              opusdec_filter
 -              opus_afh
 -              opus_common
 -      "
 -NEED_FLAC_OBJECTS && {
 -      play_errlist_objs="$play_errlist_objs flacdec_filter flac_afh"
 -}
 -if test $HAVE_FAAD = yes; then
 -      play_errlist_objs="$play_errlist_objs aac_afh aacdec_filter mp4"
 -fi
 -if test $HAVE_MAD = yes; then
 -      play_errlist_objs="$play_errlist_objs mp3dec_filter"
 -fi
 -if test $HAVE_OSS = yes; then
 -      play_errlist_objs="$play_errlist_objs oss_write"
 -fi
 -if test $HAVE_ALSA = yes; then
 -      play_errlist_objs="$play_errlist_objs alsa_write"
 -fi
 -NEED_AO_OBJECTS && {
 -      play_errlist_objs="$play_errlist_objs ao_write"
 -}
 -if test $HAVE_READLINE = yes; then
 -      play_errlist_objs="$play_errlist_objs interactive"
 -fi
 -if test $HAVE_SAMPLERATE = yes; then
 -      play_errlist_objs="$play_errlist_objs resample_filter check_wav"
 -fi
 -
 -play_objs="$play_errlist_objs"
 -AC_SUBST(play_objs, add_dot_o($play_objs))
 -######################################################################### write
 -write_errlist_objs="
 -      write
 -      write_common
 -      file_write
 -      time
 -      fd
 -      string
 -      sched
 -      stdin
 -      buffer_tree
 -      check_wav
 -      version
 -"
 -
 -NEED_AO_OBJECTS && {
 -      write_errlist_objs="$write_errlist_objs ao_write"
 -}
 -if test $HAVE_OSS = yes; then
 -      write_errlist_objs="$write_errlist_objs oss_write"
 -fi
 -if test $HAVE_ALSA = yes; then
 -      write_errlist_objs="$write_errlist_objs alsa_write"
 -fi
 -write_objs="$write_errlist_objs"
 -AC_SUBST(write_objs, add_dot_o($write_objs))
 -######################################################################## audioc
 -audioc_errlist_objs="
 -      audioc
 -      string
 -      lsu
 -      net
 -      fd
 -      time
 -      version
 -"
 -if test $HAVE_READLINE = yes; then
 -      audioc_errlist_objs="$audioc_errlist_objs
 -              buffer_tree
 -              interactive
 -              sched
 -      "
 -fi
 -audioc_objs="$audioc_errlist_objs"
 -AC_SUBST(audioc_objs, add_dot_o($audioc_objs))
 -
 -AC_DEFINE_UNQUOTED(AUDIO_FORMAT_HANDLERS, "$audio_format_handlers",
 -      [formats supported by para_server and para_afh])
 -AC_SUBST(executables)
  
  AC_OUTPUT
 -AC_MSG_NOTICE([
 -paraslash configuration:
 -~~~~~~~~~~~~~~~~~~~~~~~~
 -crypto lib: ${CRYPTOLIB:-[none]}
 -unix socket credentials: $have_ucred
 -readline (interactive CLIs): $HAVE_READLINE
 -id3 version 2 support: $HAVE_ID3TAG
 -faad: $HAVE_FAAD
 -audio format handlers: $audio_format_handlers
 -
 -exe: $executables
 -para_server: $build_server
 -para_gui: $build_gui
 -para_mixer: $build_mixer
 -para_client: $build_client
 -para_audiod: $build_audiod
 -])
diff --combined openssl.c
index 13550e7a9f34e1771932d05ef7fea5fed8c109d6,0ab047dba413d5074e2fb14bf814f5b9cc0a1dcc..a5a6a17576989ed51fbe36c116effb3ae0679f1a
+++ b/openssl.c
  
  struct asymmetric_key {
        RSA *rsa;
+       EVP_PKEY *pkey;
+       EVP_PKEY_CTX *ctx;
  };
  
+ static int openssl_perror(const char *pfx)
+ {
+       unsigned long err = ERR_get_error();
+       PARA_ERROR_LOG("%s: \"%s\"\n", pfx, ERR_reason_error_string(err));
+       return -E_OPENSSL;
+ }
  void get_random_bytes_or_die(unsigned char *buf, int num)
  {
-       unsigned long err;
+       int ret;
  
-       /* RAND_bytes() returns 1 on success, 0 otherwise. */
-       if (RAND_bytes(buf, num) == 1)
+       if (RAND_bytes(buf, num) == 1) /* success */
                return;
-       err = ERR_get_error();
-       PARA_EMERG_LOG("%s\n", ERR_reason_error_string(err));
+       ret = openssl_perror("RAND_bytes");
+       PARA_EMERG_LOG("%s\n", strerror(-ret));
        exit(EXIT_FAILURE);
  }
  
@@@ -54,6 -62,9 +62,6 @@@ void crypt_init(void
  
  void crypt_shutdown(void)
  {
 -#ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA
 -      CRYPTO_cleanup_all_ex_data();
 -#endif
  #ifdef HAVE_OPENSSL_THREAD_STOP /* openssl-1.1 or later */
        OPENSSL_thread_stop();
  #else /* openssl-1.0 */
@@@ -94,88 -105,155 +102,155 @@@ static int read_bignum(const unsigned c
        return bnsize + 4;
  }
  
- static int read_public_key(const unsigned char *blob, int blen, RSA **result)
+ #ifdef HAVE_OSSL_PARAM /* openssl-3 */
+ static int generate_private_pkey(struct asymmetric_key *priv,
+               const BIGNUM *n, const BIGNUM *e, const BIGNUM *d,
+               const BIGNUM *p, const BIGNUM *q)
  {
-       int ret;
-       RSA *rsa;
-       BIGNUM *n, *e;
+       const BIGNUM *bignums[] = {n, e, d, p, q};
+       const char *strings[] = {"n", "e", "d", "p", "q"};
+       int ret, bytes[ARRAY_SIZE(bignums)];
+       unsigned char *bufs[ARRAY_SIZE(bignums)];
+       OSSL_PARAM params[ARRAY_SIZE(bignums) + 1];
+       /*
+        * Convert bignums to buffers for OSSL_PARAM_construct_BN() and init
+        * params[].
+        */
+       for (int i = 0; i < ARRAY_SIZE(bignums); i++) {
+               bytes[i] = BN_num_bytes(bignums[i]);
+               PARA_DEBUG_LOG("%s: %d bits\n", strings[i], bytes[i] * 8);
+               bufs[i] = alloc(bytes[i]);
+               assert(BN_bn2nativepad(bignums[i], bufs[i], bytes[i]) > 0);
+               params[i] = OSSL_PARAM_construct_BN(strings[i], bufs[i],
+                       bytes[i]);
+       }
+       params[ARRAY_SIZE(bignums)] = OSSL_PARAM_construct_end();
+       /* Transfer buffers to openssl to create the pkey from it */
+       priv->ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
+       assert(priv->ctx);
+       assert(EVP_PKEY_fromdata_init(priv->ctx) > 0);
+       ret = EVP_PKEY_fromdata(priv->ctx, &priv->pkey,
+               EVP_PKEY_KEYPAIR, params);
+       for (int i = 0; i < ARRAY_SIZE(bignums); i++)
+               free(bufs[i]);
+       if (ret <= 0) {
+               EVP_PKEY_CTX_free(priv->ctx);
+               return openssl_perror("EVP_PKEY_fromdata()");
+       }
+       assert(priv->pkey);
+       return BN_num_bytes(n) * 8;
+ }
+ /*
+  * Convert bignumns e and n to a pkey and context.
+  */
+ static int generate_public_pkey(struct asymmetric_key *pub,
+               const BIGNUM *e, const BIGNUM *n)
+ {
+       unsigned char *ebuf, *nbuf;
+       int ret, ebytes = BN_num_bytes(e), nbytes = BN_num_bytes(n);
+       OSSL_PARAM params[3];
+       /* Convert e and n to a buffer for OSSL_PARAM_construct_BN() */
+       ebuf = alloc(ebytes);
+       assert(BN_bn2nativepad(e, ebuf, ebytes) > 0);
+       nbuf = alloc(nbytes);
+       assert(BN_bn2nativepad(n, nbuf, nbytes) > 0);
+       /* Init params[] with {e,n}buf and create the pkey from it */
+       params[0] = OSSL_PARAM_construct_BN("e", ebuf, ebytes);
+       params[1] = OSSL_PARAM_construct_BN("n", nbuf, nbytes);
+       params[2] = OSSL_PARAM_construct_end();
+       pub->ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
+       assert(pub->ctx);
+       assert(EVP_PKEY_fromdata_init(pub->ctx) > 0);
+       ret = EVP_PKEY_fromdata(pub->ctx, &pub->pkey, EVP_PKEY_PUBLIC_KEY,
+               params);
+       free(nbuf);
+       free(ebuf);
+       if (ret <= 0) {
+               EVP_PKEY_CTX_free(pub->ctx);
+               return openssl_perror("EVP_PKEY_fromdata()");
+       }
+       assert(pub->pkey);
+       return nbytes * 8;
+ }
+ #endif /* HAVE_OSSL_PARAM */
+ static int read_public_key(const unsigned char *blob, size_t blen,
+               struct asymmetric_key *pub)
+ {
+       int ret, bits;
        const unsigned char *p = blob, *end = blob + blen;
+       BIGNUM *e, *n;
  
-       rsa = RSA_new();
-       if (!rsa)
-               return -E_BIGNUM;
        ret = read_bignum(p, end - p, &e);
        if (ret < 0)
-               goto free_rsa;
+               return ret;
        p += ret;
        ret = read_bignum(p, end - p, &n);
-       if (ret < 0)
-               goto free_e;
- #ifdef HAVE_RSA_SET0_KEY
-       RSA_set0_key(rsa, n, e, NULL);
- #else
-       rsa->n = n;
-       rsa->e = e;
- #endif
-       *result = rsa;
-       return 1;
- free_e:
+       if (ret < 0) {
+               BN_free(e);
+               return ret;
+       }
+       bits = BN_num_bytes(n) * 8;
+       PARA_DEBUG_LOG("modulus: %d bits\n", bits);
+ #ifdef HAVE_OSSL_PARAM /* openssl-3 */
+       ret = generate_public_pkey(pub, e, n);
        BN_free(e);
- free_rsa:
-       RSA_free(rsa);
-       return ret;
+       BN_free(n);
+       if (ret < 0)
+               return ret;
+ #else /* openssl < 3.0 */
+       pub->rsa = RSA_new();
+       assert(pub->rsa);
+       #if HAVE_RSA_SET0_KEY /* openssl-1.1 */
+               RSA_set0_key(pub->rsa, n, e, NULL);
+       #else /* openssl-1.0 */
+               pub->rsa->n = n;
+               pub->rsa->e = e;
+       #endif
+       /* e and n are now owned by openssl */
+ #endif /* HAVE_OSSL_PARAM */
+       return bits;
  }
  
- static int read_pem_private_key(const char *path, RSA **rsa)
+ static int read_pem_private_key(const char *path, struct asymmetric_key *priv)
  {
-       EVP_PKEY *pkey;
-       BIO *bio = BIO_new(BIO_s_file());
-       *rsa = NULL;
-       if (!bio)
-               return -E_PRIVATE_KEY;
-       if (BIO_read_filename(bio, path) <= 0)
-               goto bio_free;
-       pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
-       if (!pkey)
-               goto bio_free;
-       *rsa = EVP_PKEY_get1_RSA(pkey);
-       EVP_PKEY_free(pkey);
- bio_free:
+       BIO *bio;
+       int ret;
+       assert((bio = BIO_new(BIO_s_file())));
+       ret = BIO_read_filename(bio, path);
+       if (ret <= 0) {
+               priv->pkey = NULL;
+               ret = openssl_perror("BIO_read_filename");
+               goto free_bio;
+       }
+       priv->pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
+       if (!priv->pkey) {
+               ret = openssl_perror("PEM_read_bio_PrivateKey");
+               goto free_bio;
+       }
+ #ifndef HAVE_OSSL_PARAM /* openssl-1 */
+       priv->rsa = EVP_PKEY_get1_RSA(priv->pkey);
+ #endif
+ free_bio:
        BIO_free(bio);
-       return *rsa? RSA_size(*rsa) : -E_PRIVATE_KEY;
+       return ret;
  }
  
  static int read_openssh_private_key(const unsigned char *blob,
-               const unsigned char *end, RSA **result)
+               const unsigned char *end, struct asymmetric_key *priv)
  {
        int ret;
-       RSA *rsa;
-       BN_CTX *ctx;
        BIGNUM *n, *e, *d, *iqmp, *p, *q; /* stored in the key file */
-       BIGNUM *dmp1, *dmq1; /* these will be computed */
-       BIGNUM *tmp;
        const unsigned char *cp = blob;
  
-       rsa = RSA_new();
-       if (!rsa)
-               return -E_BIGNUM;
-       ret = -E_BIGNUM;
-       tmp = BN_new();
-       if (!tmp)
-               goto free_rsa;
-       ctx = BN_CTX_new();
-       if (!ctx)
-               goto free_tmp;
-       dmp1 = BN_new();
-       if (!dmp1)
-               goto free_ctx;
-       dmq1 = BN_new();
-       if (!dmq1)
-               goto free_dmp1;
        ret = read_bignum(cp, end - cp, &n);
        if (ret < 0)
-               goto free_dmq1;
+               return ret;
        cp += ret;
        ret = read_bignum(cp, end - cp, &e);
        if (ret < 0)
        ret = read_bignum(cp, end - cp, &q);
        if (ret < 0)
                goto free_p;
-       ret = -E_BIGNUM;
-       if (!BN_sub(tmp, q, BN_value_one()))
-               goto free_q;
-       if (!BN_mod(dmp1, d, tmp, ctx))
-               goto free_q;
-       if (!BN_sub(tmp, q, BN_value_one()))
-               goto free_q;
-       if (!BN_mod(dmq1, d, tmp, ctx))
-               goto free_q;
- #ifdef HAVE_RSA_SET0_KEY
-       RSA_set0_key(rsa, n, e, d);
-       RSA_set0_factors(rsa, p, q);
-       RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp);
+ #ifdef HAVE_OSSL_PARAM /* openssl-3 */
+       /*
+        * Ignore iqmp, the coefficient for Chinese remainder theorem. It is
+        * dispensable because it can be derived from the other values. Passing
+        * it to the EVP API results in a memory leak.
+        */
+       ret = generate_private_pkey(priv, n, e, d, p, q);
  #else
-       rsa->n = n;
-       rsa->e = e;
-       rsa->d = d;
-       rsa->iqmp = iqmp;
-       rsa->p = p;
-       rsa->q = q;
-       rsa->dmp1 = dmp1;
-       rsa->dmq1 = dmq1;
- #endif
-       *result = rsa;
-       ret = 1;
-       goto free_ctx;
- free_q:
+       assert((priv->rsa = RSA_new()));
+       #ifdef HAVE_RSA_SET0_KEY
+               RSA_set0_key(priv->rsa, n, e, d);
+               RSA_set0_factors(priv->rsa, p, q);
+               RSA_set0_crt_params(priv->rsa, NULL, NULL, iqmp);
+       #else
+               priv->rsa->n = n;
+               priv->rsa->e = e;
+               priv->rsa->d = d;
+               priv->rsa->iqmp = iqmp;
+               priv->rsa->p = p;
+               priv->rsa->q = q;
+       #endif
+       return 1;
+ #endif /* HAVE_OSSL_PARAM */
        BN_clear_free(q);
  free_p:
        BN_clear_free(p);
@@@ -234,27 -308,15 +305,15 @@@ free_e
        BN_free(e);
  free_n:
        BN_free(n);
- free_dmq1:
-       BN_clear_free(dmq1);
- free_dmp1:
-       BN_clear_free(dmp1);
- free_ctx:
-       BN_CTX_free(ctx);
- free_tmp:
-       BN_clear_free(tmp);
- free_rsa:
-       if (ret < 0)
-               RSA_free(rsa);
        return ret;
  }
  
- static int get_private_key(const char *path, RSA **rsa)
+ static int get_private_key(const char *path, struct asymmetric_key *priv)
  {
        int ret;
        unsigned char *blob, *end;
        size_t blob_size;
  
-       *rsa = NULL;
        ret = decode_private_key(path, &blob, &blob_size);
        if (ret < 0)
                return ret;
                if (ret < 0)
                        goto free_blob;
                PARA_INFO_LOG("reading RSA params at offset %d\n", ret);
-               ret = read_openssh_private_key(blob + ret, end, rsa);
+               ret = read_openssh_private_key(blob + ret, end, priv);
        } else
-               ret = read_pem_private_key(path, rsa);
+               ret = read_pem_private_key(path, priv);
  free_blob:
        free(blob);
        return ret;
@@@ -277,53 -339,84 +336,84 @@@ int apc_get_pubkey(const char *key_file
        unsigned char *blob;
        size_t decoded_size;
        int ret;
-       struct asymmetric_key *pub = alloc(sizeof(*pub));
+       struct asymmetric_key *pub;
  
        ret = decode_public_key(key_file, &blob, &decoded_size);
        if (ret < 0)
-               goto out;
-       ret = read_public_key(blob + ret, decoded_size - ret, &pub->rsa);
-       if (ret < 0)
-               goto free_blob;
-       ret = RSA_size(pub->rsa);
-       assert(ret > 0);
-       *result = pub;
- free_blob:
+               return ret;
+       pub = zalloc(sizeof(*pub)); /* ->pkey needs to start out zeroed */
+       ret = read_public_key(blob + ret, decoded_size - ret, pub);
        free(blob);
- out:
        if (ret < 0) {
                free(pub);
                *result = NULL;
                PARA_ERROR_LOG("can not load key %s\n", key_file);
+               return ret;
        }
-       return ret;
+       PARA_NOTICE_LOG("loaded %d bit key from %s\n", ret, key_file);
+       *result = pub;
+       return ret / 8;
  }
  
  void apc_free_pubkey(struct asymmetric_key *pub)
  {
        if (!pub)
                return;
+ #ifdef HAVE_OSSL_PARAM /* openssl-3 */
+       EVP_PKEY_CTX_free(pub->ctx);
+       EVP_PKEY_free(pub->pkey);
+ #else
        RSA_free(pub->rsa);
+ #endif
        free(pub);
  }
  
- int apc_priv_decrypt(const char *key_file, unsigned char *outbuf,
+ #ifdef HAVE_OSSL_PARAM /* openssl-3 */
+ static int pkey_priv_decrypt(const struct asymmetric_key *priv,
+               unsigned char **outbuf, unsigned char *inbuf, int inlen)
+ {
+       EVP_PKEY_CTX *ctx;
+       size_t outlen;
+       assert((ctx = EVP_PKEY_CTX_new(priv->pkey, NULL)));
+       assert((EVP_PKEY_decrypt_init(ctx) > 0));
+       assert(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) > 0);
+       if (EVP_PKEY_decrypt(ctx, NULL, &outlen, inbuf, inlen) <= 0) {
+               *outbuf = NULL;
+               EVP_PKEY_CTX_free(ctx);
+               return openssl_perror("EVP_PKEY_encrypt()");
+       }
+       *outbuf = alloc(outlen);
+       assert((EVP_PKEY_decrypt(ctx, *outbuf, &outlen, inbuf, inlen) > 0));
+       EVP_PKEY_CTX_free(ctx);
+       PARA_INFO_LOG("wrote %zu decrypted data bytes\n", outlen);
+       return outlen;
+ }
+ #endif /* HAVE_OSSL_PARAM */
+ int apc_priv_decrypt(const char *key_file, unsigned char **outbuf,
                unsigned char *inbuf, int inlen)
  {
        struct asymmetric_key *priv;
        int ret;
  
+       *outbuf = NULL;
        ret = check_private_key_file(key_file);
        if (ret < 0)
                return ret;
        if (inlen < 0)
                return -E_RSA;
-       priv = alloc(sizeof(*priv));
-       ret = get_private_key(key_file, &priv->rsa);
+       priv = zalloc(sizeof(*priv)); /* ->pkey needs to start out zeroed */
+       ret = get_private_key(key_file, priv);
        if (ret < 0) {
                free(priv);
                return ret;
        }
+ #ifdef HAVE_OSSL_PARAM /* openssl-3 */
+       ret = pkey_priv_decrypt(priv, outbuf, inbuf, inlen);
+       EVP_PKEY_CTX_free(priv->ctx);
+       EVP_PKEY_free(priv->pkey);
+ #else
        /*
         * RSA is vulnerable to timing attacks. Generate a random blinding
         * factor to protect against this kind of attack.
        ret = -E_BLINDING;
        if (RSA_blinding_on(priv->rsa, NULL) == 0)
                goto out;
-       ret = RSA_private_decrypt(inlen, inbuf, outbuf, priv->rsa,
+       *outbuf = alloc(RSA_size(priv->rsa));
+       ret = RSA_private_decrypt(inlen, inbuf, *outbuf, priv->rsa,
                RSA_PKCS1_OAEP_PADDING);
        RSA_blinding_off(priv->rsa);
-       if (ret <= 0)
+       if (ret <= 0) {
+               free(*outbuf);
+               *outbuf = NULL;
                ret = -E_DECRYPT;
+       }
  out:
        RSA_free(priv->rsa);
+ #endif
        free(priv);
        return ret;
  }
  
  int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf,
-               unsigned len, unsigned char *outbuf)
+               unsigned len, unsigned char **outbuf)
  {
-       int ret, flen = len; /* RSA_public_encrypt expects a signed int */
-       if (flen < 0)
-               return -E_ENCRYPT;
-       ret = RSA_public_encrypt(flen, inbuf, outbuf, pub->rsa,
+       int ret;
+ #ifdef HAVE_OSSL_PARAM /* openssl-3 */
+       EVP_PKEY_CTX *ctx;
+       size_t outlen;
+       *outbuf = NULL;
+       assert((ctx = EVP_PKEY_CTX_new(pub->pkey, NULL)));
+       assert((EVP_PKEY_encrypt_init(ctx) > 0));
+       assert((EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) > 0));
+       if (EVP_PKEY_encrypt(ctx, NULL, &outlen, inbuf, len) <= 0) {
+               ret = openssl_perror("EVP_PKEY_encrypt()");
+               goto free_ctx;
+       }
+       *outbuf = alloc(outlen);
+       assert((EVP_PKEY_encrypt(ctx, *outbuf, &outlen, inbuf, len) > 0));
+       PARA_INFO_LOG("wrote %zu encrypted data bytes\n", outlen);
+       ret = outlen;
+ free_ctx:
+       EVP_PKEY_CTX_free(ctx);
+       return ret;
+ #else /* openssl < 3.0 */
+       *outbuf = alloc(RSA_size(pub->rsa));
+       ret = RSA_public_encrypt((int)len, inbuf, *outbuf, pub->rsa,
                RSA_PKCS1_OAEP_PADDING);
-       return ret < 0? -E_ENCRYPT : ret;
+       if (ret < 0) {
+               free(*outbuf);
+               *outbuf = NULL;
+               return -E_ENCRYPT;
+       }
+       return ret;
+ #endif /* HAVE_OSSL_PARAM */
  }
  
  struct stream_cipher {
@@@ -363,7 -485,7 +482,7 @@@ struct stream_cipher *sc_new(const unsi
        struct stream_cipher *sc = alloc(sizeof(*sc));
  
        assert(len >= 2 * AES_CRT128_BLOCK_SIZE);
-       sc->aes = EVP_CIPHER_CTX_new();
+       assert((sc->aes = EVP_CIPHER_CTX_new()));
        EVP_EncryptInit_ex(sc->aes, EVP_aes_128_ctr(), NULL, data,
                data + AES_CRT128_BLOCK_SIZE);
        return sc;
@@@ -403,8 -525,11 +522,11 @@@ void sc_crypt(struct stream_cipher *sc
  
  void hash_function(const char *data, unsigned long len, unsigned char *hash)
  {
-       EVP_MD_CTX *c = EVP_MD_CTX_new();
-       int ret = EVP_DigestInit_ex(c, EVP_sha1(), NULL);
+       int ret;
+       EVP_MD_CTX *c;
+       assert((c = EVP_MD_CTX_new()));
+       ret = EVP_DigestInit_ex(c, EVP_sha1(), NULL);
        assert(ret != 0);
        ret = EVP_DigestUpdate(c, data, len);
        assert(ret != 0);
  
  void hash2_function(const char *data, unsigned long len, unsigned char *hash)
  {
-       EVP_MD_CTX *c = EVP_MD_CTX_new();
-       int ret = EVP_DigestInit_ex(c, EVP_sha256(), NULL);
+       int ret;
+       EVP_MD_CTX *c;
+       assert((c = EVP_MD_CTX_new()));
+       ret = EVP_DigestInit_ex(c, EVP_sha256(), NULL);
        assert(ret != 0);
        ret = EVP_DigestUpdate(c, data, len);
        assert(ret != 0);