From 0d7157c16714fd69974a9e30eabe9a9586862889 Mon Sep 17 00:00:00 2001 From: Riza Sulistyo Date: Fri, 8 Jul 2022 09:25:38 +0700 Subject: [PATCH] Support OpenSSL3 (#3168) * Support OpenSSL3 * Modify code order --- pjlib/src/pj/ssl_sock_ossl.c | 115 +++++++++++++++++++++--------- pjsip/src/pjsip/sip_auth_client.c | 61 +++++++++++++++- 2 files changed, 141 insertions(+), 35 deletions(-) diff --git a/pjlib/src/pj/ssl_sock_ossl.c b/pjlib/src/pj/ssl_sock_ossl.c index 180ef0fe6..ba7f8fa5c 100644 --- a/pjlib/src/pj/ssl_sock_ossl.c +++ b/pjlib/src/pj/ssl_sock_ossl.c @@ -57,6 +57,10 @@ #include #include +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +# include +#endif + /* Specify whether server supports session reuse using session ID. */ #define SERVER_SUPPORT_SESSION_REUSE 1 @@ -255,6 +259,18 @@ static char *SSLErrorString (int err) } } +# if OPENSSL_VERSION_NUMBER >= 0x30000000L +#define ERROR_LOG(msg, err, ssock) \ +{ \ + char err_str[PJ_ERR_MSG_SIZE]; \ + char buf[PJ_INET6_ADDRSTRLEN + 10]; \ + ERR_error_string_n(err, err_str, sizeof(err_str)); \ + PJ_LOG(2,("SSL", "%s (%s): Level: %d err: <%lu> <%s> len: %d peer: %s", \ + msg, action, level, err, err_str, len, \ + (ssock && pj_sockaddr_has_addr(&ssock->rem_addr)? \ + pj_sockaddr_print(&ssock->rem_addr, buf, sizeof(buf), 3):"???")));\ +} +# else #define ERROR_LOG(msg, err, ssock) \ { \ char buf[PJ_INET6_ADDRSTRLEN+10]; \ @@ -268,6 +284,7 @@ static char *SSLErrorString (int err) (ssock && pj_sockaddr_has_addr(&ssock->rem_addr)? \ pj_sockaddr_print(&ssock->rem_addr, buf, sizeof(buf), 3):"???")));\ } +# endif static void SSLLogErrors(char * action, int ret, int ssl_err, int len, pj_ssl_sock_t *ssock) @@ -656,6 +673,7 @@ static pj_status_t init_openssl(void) openssl_init_count = 1; + PJ_LOG(4, (THIS_FILE, "OpenSSL version : %x", OPENSSL_VERSION_NUMBER)); /* Register error subsystem */ status = pj_register_strerror(PJ_SSL_ERRNO_START, PJ_SSL_ERRNO_SPACE_SIZE, @@ -1030,16 +1048,63 @@ static int xname_cmp(const X509_NAME **a, const X509_NAME **b) { #endif +#if !defined(OPENSSL_NO_DH) + +static void set_option(const pj_ssl_sock_t* ssock, SSL_CTX* ctx) { + unsigned long options = SSL_OP_CIPHER_SERVER_PREFERENCE | +#if !defined(OPENSSL_NO_ECDH) && OPENSSL_VERSION_NUMBER >= 0x10000000L + SSL_OP_SINGLE_ECDH_USE | +#endif + SSL_OP_SINGLE_DH_USE; + options = SSL_CTX_set_options(ctx, options); + PJ_LOG(4, (ssock->pool->obj_name, "SSL DH " + "initialized, PFS cipher-suites enabled")); +} + +static void set_dh_use_option(BIO *bio, const pj_ssl_sock_t* ssock, + const pj_str_t *pass, SSL_CTX* ctx) +{ +#if OPENSSL_VERSION_NUMBER < 0x30000000L + DH* dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); + if (dh != NULL) { + if (SSL_CTX_set_tmp_dh(ctx, dh)) { + set_option(ssock, ctx); + } + DH_free(dh); + } +#else + OSSL_DECODER_CTX* dctx; + EVP_PKEY* dh_pkey = NULL; + const char* format = "PEM"; + const char* structure = NULL; + const char* keytype = NULL; + + dctx = OSSL_DECODER_CTX_new_for_pkey(&dh_pkey, format, structure, keytype, + 0, NULL, NULL); + if (dctx != NULL) { + if (pass->slen) { + OSSL_DECODER_CTX_set_passphrase(dctx, + (const unsigned char*)pass->ptr, + pass->slen); + } + + if (OSSL_DECODER_from_bio(dctx, bio)) { + if (SSL_CTX_set0_tmp_dh_pkey(ctx, dh_pkey)) { + set_option(ssock, ctx); + } + } + OSSL_DECODER_CTX_free(dctx); + } +#endif +} + +#endif + /* Initialize OpenSSL context for the ssock */ static pj_status_t init_ossl_ctx(pj_ssl_sock_t *ssock) { ossl_sock_t *ossock = (ossl_sock_t *)ssock; SSL_CTX *ctx = NULL; -#if !defined(OPENSSL_NO_DH) - BIO *bio; - DH *dh; - long options; -#endif SSL_METHOD *ssl_method = NULL; pj_uint32_t ssl_opt = 0; pj_ssl_cert_t *cert = ssock->cert; @@ -1121,6 +1186,14 @@ static pj_status_t init_ossl_ctx(pj_ssl_sock_t *ssock) return GET_SSL_STATUS(ssock); } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (ssock->param.proto <= PJ_SSL_SOCK_PROTO_TLS1_1) { + /* TLS 1.0, TLS 1.1 no longer working at the default security + * level of 1 and instead requires security level 0. */ + SSL_CTX_set_security_level(ossock->ossl_ctx, 0); + } +#endif + if (ssock->is_server) { unsigned int sid_ctx = SERVER_SESSION_ID_CONTEXT; @@ -1237,22 +1310,9 @@ static pj_status_t init_ossl_ctx(pj_ssl_sock_t *ssock) #if !defined(OPENSSL_NO_DH) if (ssock->is_server) { - bio = BIO_new_file(cert->privkey_file.ptr, "r"); + BIO *bio = BIO_new_file(cert->privkey_file.ptr, "r"); if (bio != NULL) { - dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); - if (dh != NULL) { - if (SSL_CTX_set_tmp_dh(ctx, dh)) { - options = SSL_OP_CIPHER_SERVER_PREFERENCE | - #if !defined(OPENSSL_NO_ECDH) && OPENSSL_VERSION_NUMBER >= 0x10000000L - SSL_OP_SINGLE_ECDH_USE | - #endif - SSL_OP_SINGLE_DH_USE; - options = SSL_CTX_set_options(ctx, options); - PJ_LOG(4,(ssock->pool->obj_name, "SSL DH " - "initialized, PFS cipher-suites enabled")); - } - DH_free(dh); - } + set_dh_use_option(bio, ssock, &cert->privkey_pass, ctx); BIO_free(bio); } } @@ -1359,20 +1419,7 @@ static pj_status_t init_ossl_ctx(pj_ssl_sock_t *ssock) } if (ssock->is_server) { - dh = PEM_read_bio_DHparams(kbio, NULL, NULL, NULL); - if (dh != NULL) { - if (SSL_CTX_set_tmp_dh(ctx, dh)) { - options = SSL_OP_CIPHER_SERVER_PREFERENCE | - #if !defined(OPENSSL_NO_ECDH) && OPENSSL_VERSION_NUMBER >= 0x10000000L - SSL_OP_SINGLE_ECDH_USE | - #endif - SSL_OP_SINGLE_DH_USE; - options = SSL_CTX_set_options(ctx, options); - PJ_LOG(4,(ssock->pool->obj_name, "SSL DH " - "initialized, PFS cipher-suites enabled")); - } - DH_free(dh); - } + set_dh_use_option(kbio, ssock, &cert->privkey_pass, ctx); } BIO_free(kbio); } diff --git a/pjsip/src/pjsip/sip_auth_client.c b/pjsip/src/pjsip/sip_auth_client.c index ab1a0cd87..29b5eecb1 100644 --- a/pjsip/src/pjsip/sip_auth_client.c +++ b/pjsip/src/pjsip/sip_auth_client.c @@ -45,6 +45,9 @@ #if PJSIP_AUTH_HAS_DIGEST_SHA256 # include +# if OPENSSL_VERSION_NUMBER >= 0x30000000L +# include +# endif # ifdef _MSC_VER # include # if OPENSSL_VERSION_NUMBER >= 0x10100000L @@ -276,10 +279,24 @@ PJ_DEF(pj_status_t) pjsip_auth_create_digestSHA256(pj_str_t *result, char ha1[PJSIP_SHA256STRLEN]; char ha2[PJSIP_SHA256STRLEN]; unsigned char digest[32]; + +#if OPENSSL_VERSION_NUMBER < 0x30000000L SHA256_CTX pms; +#else + EVP_MD_CTX* mdctx; + const EVP_MD* md; + unsigned dig_len; +#endif pj_assert(result->slen >= PJSIP_SHA256STRLEN); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + md = EVP_get_digestbyname("SHA256"); + if (md == NULL) { + return PJ_ENOTSUP; + } +#endif + AUTH_TRACE_((THIS_FILE, "Begin creating digest")); if ((cred_info->data_type & PASSWD_MASK) == PJSIP_CRED_DATA_PLAIN_PASSWD) @@ -287,6 +304,7 @@ PJ_DEF(pj_status_t) pjsip_auth_create_digestSHA256(pj_str_t *result, /*** *** ha1 = SHA256(username ":" realm ":" password) ***/ +#if OPENSSL_VERSION_NUMBER < 0x30000000L SHA256_Init(&pms); SHA256_Update( &pms, cred_info->username.ptr, cred_info->username.slen); @@ -295,7 +313,18 @@ PJ_DEF(pj_status_t) pjsip_auth_create_digestSHA256(pj_str_t *result, SHA256_Update( &pms, ":", 1); SHA256_Update( &pms, cred_info->data.ptr, cred_info->data.slen); SHA256_Final(digest, &pms); - +#else + mdctx = EVP_MD_CTX_new(); + EVP_DigestInit_ex(mdctx, md, NULL); + EVP_DigestUpdate(mdctx, cred_info->username.ptr, cred_info->username.slen); + EVP_DigestUpdate(mdctx, ":", 1); + EVP_DigestUpdate(mdctx, realm->ptr, realm->slen); + EVP_DigestUpdate(mdctx, ":", 1); + EVP_DigestUpdate(mdctx, cred_info->data.ptr, cred_info->data.slen); + + EVP_DigestFinal_ex(mdctx, digest, &dig_len); + EVP_MD_CTX_free(mdctx); +#endif digestNtoStr(digest, 32, ha1); } else if ((cred_info->data_type & PASSWD_MASK) == PJSIP_CRED_DATA_DIGEST) @@ -319,11 +348,21 @@ PJ_DEF(pj_status_t) pjsip_auth_create_digestSHA256(pj_str_t *result, /*** *** ha2 = SHA256(method ":" req_uri) ***/ +#if OPENSSL_VERSION_NUMBER < 0x30000000L SHA256_Init(&pms); SHA256_Update( &pms, method->ptr, method->slen); SHA256_Update( &pms, ":", 1); SHA256_Update( &pms, uri->ptr, uri->slen); SHA256_Final( digest, &pms); +#else + mdctx = EVP_MD_CTX_new(); + EVP_DigestInit_ex(mdctx, md, NULL); + EVP_DigestUpdate(mdctx, method->ptr, method->slen); + EVP_DigestUpdate(mdctx, ":", 1); + EVP_DigestUpdate(mdctx, uri->ptr, uri->slen); + EVP_DigestFinal_ex(mdctx, digest, &dig_len); + EVP_MD_CTX_free(mdctx); +#endif digestNtoStr(digest, 32, ha2); AUTH_TRACE_((THIS_FILE, " ha2=%.64s", ha2)); @@ -335,6 +374,7 @@ PJ_DEF(pj_status_t) pjsip_auth_create_digestSHA256(pj_str_t *result, *** When qop=auth is used: *** response = SHA256(ha1 ":" nonce ":" nc ":" cnonce ":" qop ":" ha2) ***/ +#if OPENSSL_VERSION_NUMBER < 0x30000000L SHA256_Init(&pms); SHA256_Update( &pms, ha1, PJSIP_SHA256STRLEN); SHA256_Update( &pms, ":", 1); @@ -352,7 +392,26 @@ PJ_DEF(pj_status_t) pjsip_auth_create_digestSHA256(pj_str_t *result, /* This is the final response digest. */ SHA256_Final(digest, &pms); +#else + mdctx = EVP_MD_CTX_new(); + EVP_DigestInit_ex(mdctx, md, NULL); + EVP_DigestUpdate(mdctx, ha1, PJSIP_SHA256STRLEN); + EVP_DigestUpdate(mdctx, ":", 1); + EVP_DigestUpdate(mdctx, nonce->ptr, nonce->slen); + if (qop && qop->slen != 0) { + EVP_DigestUpdate(mdctx, ":", 1); + EVP_DigestUpdate(mdctx, nc->ptr, nc->slen); + EVP_DigestUpdate(mdctx, ":", 1); + EVP_DigestUpdate(mdctx, cnonce->ptr, cnonce->slen); + EVP_DigestUpdate(mdctx, ":", 1); + EVP_DigestUpdate(mdctx, qop->ptr, qop->slen); + } + EVP_DigestUpdate(mdctx, ":", 1); + EVP_DigestUpdate(mdctx, ha2, PJSIP_SHA256STRLEN); + EVP_DigestFinal_ex(mdctx, digest, &dig_len); + EVP_MD_CTX_free(mdctx); +#endif /* Convert digest to string and store in chal->response. */ result->slen = PJSIP_SHA256STRLEN; digestNtoStr(digest, 32, result->ptr);