7878#define EVP_MD_CTX_free (mdctx )
7979#endif
8080
81+ /*
82+ * When building with OpenSSL, MD5 may not be available (e.g., FIPS-only
83+ * configurations). Detect MD5 availability once and, if missing, fall back
84+ * to pjlib's internal MD5 implementation for MD5-based digests.
85+ */
86+ #if defined(PJ_HAS_SSL_SOCK ) && PJ_HAS_SSL_SOCK != 0 && \
87+ PJ_SSL_SOCK_IMP == PJ_SSL_SOCK_IMP_OPENSSL
88+ static int g_md5_evp_supported = -1 ; /* -1=unknown, 0=no, 1=yes */
89+ static pj_bool_t md5_evp_is_supported (void )
90+ {
91+ if (g_md5_evp_supported == -1 ) {
92+ const EVP_MD * md = EVP_get_digestbyname ("MD5" );
93+ if (!md ) {
94+ g_md5_evp_supported = 0 ;
95+ } else {
96+ EVP_MD_CTX * ctx = EVP_MD_CTX_new ();
97+ if (!ctx ) {
98+ g_md5_evp_supported = 0 ;
99+ } else {
100+ /* EVP_DigestInit_ex will fail in strict FIPS environments */
101+ g_md5_evp_supported = (EVP_DigestInit_ex (ctx , md , NULL ) == 1 ) ? 1 : 0 ;
102+ EVP_MD_CTX_free (ctx );
103+ }
104+ }
105+ }
106+ return g_md5_evp_supported ? PJ_TRUE : PJ_FALSE ;
107+ }
108+ #endif
109+
81110const pjsip_auth_algorithm pjsip_auth_algorithms [] = {
82111/* TYPE IANA name OpenSSL name */
83112/* Raw digest byte length Hex representation length */
@@ -232,6 +261,7 @@ PJ_DEF(pj_status_t) pjsip_auth_create_digest2( pj_str_t *result,
232261 unsigned dig_len = 0 ;
233262 const EVP_MD * md ;
234263 DEFINE_HASH_CONTEXT ;
264+ pj_bool_t use_builtin_md5 = PJ_FALSE ;
235265
236266 PJ_ASSERT_RETURN (result && nonce && uri && realm && cred_info && method , PJ_EINVAL );
237267 pj_bzero (result -> ptr , result -> slen );
@@ -294,8 +324,15 @@ PJ_DEF(pj_status_t) pjsip_auth_create_digest2( pj_str_t *result,
294324 }
295325
296326 md = EVP_get_digestbyname (algorithm -> openssl_name );
297- if (md == NULL ) {
298- /* Shouldn't happen since it was checked above */
327+ /* For MD5, if OpenSSL doesn't provide/allow it, we'll fallback. */
328+ #if defined(PJ_HAS_SSL_SOCK ) && PJ_HAS_SSL_SOCK != 0 && \
329+ PJ_SSL_SOCK_IMP == PJ_SSL_SOCK_IMP_OPENSSL
330+ if (algorithm -> algorithm_type == PJSIP_AUTH_ALGORITHM_MD5 && !md5_evp_is_supported ()) {
331+ use_builtin_md5 = PJ_TRUE ;
332+ }
333+ #endif
334+ if (md == NULL && !use_builtin_md5 ) {
335+ /* Shouldn't happen since it was checked above, unless provider disabled; */
299336 return PJ_ENOTSUP ;
300337 }
301338
@@ -309,17 +346,27 @@ PJ_DEF(pj_status_t) pjsip_auth_create_digest2( pj_str_t *result,
309346 /***
310347 *** ha1 = (digest)(username ":" realm ":" password)
311348 ***/
312- mdctx = EVP_MD_CTX_new ();
313-
314- EVP_DigestInit_ex (mdctx , md , NULL );
315- EVP_DigestUpdate (mdctx , cred_info -> username .ptr , cred_info -> username .slen );
316- EVP_DigestUpdate (mdctx , ":" , 1 );
317- EVP_DigestUpdate (mdctx , realm -> ptr , realm -> slen );
318- EVP_DigestUpdate (mdctx , ":" , 1 );
319- EVP_DigestUpdate (mdctx , cred_info -> data .ptr , cred_info -> data .slen );
320-
321- EVP_DigestFinal_ex (mdctx , digest , & dig_len );
322- EVP_MD_CTX_free (mdctx );
349+ if (use_builtin_md5 ) {
350+ pj_md5_context ctx ;
351+ pj_md5_init (& ctx );
352+ pj_md5_update (& ctx , (const pj_uint8_t * )cred_info -> username .ptr , (unsigned )cred_info -> username .slen );
353+ pj_md5_update (& ctx , (const pj_uint8_t * )":" , 1 );
354+ pj_md5_update (& ctx , (const pj_uint8_t * )realm -> ptr , (unsigned )realm -> slen );
355+ pj_md5_update (& ctx , (const pj_uint8_t * )":" , 1 );
356+ pj_md5_update (& ctx , (const pj_uint8_t * )cred_info -> data .ptr , (unsigned )cred_info -> data .slen );
357+ pj_md5_final (& ctx , digest );
358+ dig_len = digest_len ;
359+ } else {
360+ mdctx = EVP_MD_CTX_new ();
361+ EVP_DigestInit_ex (mdctx , md , NULL );
362+ EVP_DigestUpdate (mdctx , cred_info -> username .ptr , cred_info -> username .slen );
363+ EVP_DigestUpdate (mdctx , ":" , 1 );
364+ EVP_DigestUpdate (mdctx , realm -> ptr , realm -> slen );
365+ EVP_DigestUpdate (mdctx , ":" , 1 );
366+ EVP_DigestUpdate (mdctx , cred_info -> data .ptr , cred_info -> data .slen );
367+ EVP_DigestFinal_ex (mdctx , digest , & dig_len );
368+ EVP_MD_CTX_free (mdctx );
369+ }
323370 digestNtoStr (digest , dig_len , ha1 );
324371
325372 } else {
@@ -333,13 +380,23 @@ PJ_DEF(pj_status_t) pjsip_auth_create_digest2( pj_str_t *result,
333380 /***
334381 *** ha2 = (digest)(method ":" req_uri)
335382 ***/
336- mdctx = EVP_MD_CTX_new ();
337- EVP_DigestInit_ex (mdctx , md , NULL );
338- EVP_DigestUpdate (mdctx , method -> ptr , method -> slen );
339- EVP_DigestUpdate (mdctx , ":" , 1 );
340- EVP_DigestUpdate (mdctx , uri -> ptr , uri -> slen );
341- EVP_DigestFinal_ex (mdctx , digest , & dig_len );
342- EVP_MD_CTX_free (mdctx );
383+ if (use_builtin_md5 ) {
384+ pj_md5_context ctx ;
385+ pj_md5_init (& ctx );
386+ pj_md5_update (& ctx , (const pj_uint8_t * )method -> ptr , (unsigned )method -> slen );
387+ pj_md5_update (& ctx , (const pj_uint8_t * )":" , 1 );
388+ pj_md5_update (& ctx , (const pj_uint8_t * )uri -> ptr , (unsigned )uri -> slen );
389+ pj_md5_final (& ctx , digest );
390+ dig_len = digest_len ;
391+ } else {
392+ mdctx = EVP_MD_CTX_new ();
393+ EVP_DigestInit_ex (mdctx , md , NULL );
394+ EVP_DigestUpdate (mdctx , method -> ptr , method -> slen );
395+ EVP_DigestUpdate (mdctx , ":" , 1 );
396+ EVP_DigestUpdate (mdctx , uri -> ptr , uri -> slen );
397+ EVP_DigestFinal_ex (mdctx , digest , & dig_len );
398+ EVP_MD_CTX_free (mdctx );
399+ }
343400 digestNtoStr (digest , dig_len , ha2 );
344401
345402 AUTH_TRACE_ ((THIS_FILE , " ha2=%.*s" , algorithm -> digest_str_length , ha2 ));
@@ -351,24 +408,43 @@ PJ_DEF(pj_status_t) pjsip_auth_create_digest2( pj_str_t *result,
351408 *** When qop=auth is used:
352409 *** response = (digest)(ha1 ":" nonce ":" nc ":" cnonce ":" qop ":" ha2)
353410 ***/
354- mdctx = EVP_MD_CTX_new ();
355- EVP_DigestInit_ex (mdctx , md , NULL );
356- EVP_DigestUpdate (mdctx , ha1 , digest_strlen );
357- EVP_DigestUpdate (mdctx , ":" , 1 );
358- EVP_DigestUpdate (mdctx , nonce -> ptr , nonce -> slen );
359- if (qop && qop -> slen != 0 ) {
360- EVP_DigestUpdate (mdctx , ":" , 1 );
361- EVP_DigestUpdate (mdctx , nc -> ptr , nc -> slen );
411+ if (use_builtin_md5 ) {
412+ pj_md5_context ctx ;
413+ pj_md5_init (& ctx );
414+ pj_md5_update (& ctx , (const pj_uint8_t * )ha1 , (unsigned )digest_strlen );
415+ pj_md5_update (& ctx , (const pj_uint8_t * )":" , 1 );
416+ pj_md5_update (& ctx , (const pj_uint8_t * )nonce -> ptr , (unsigned )nonce -> slen );
417+ if (qop && qop -> slen != 0 ) {
418+ pj_md5_update (& ctx , (const pj_uint8_t * )":" , 1 );
419+ pj_md5_update (& ctx , (const pj_uint8_t * )nc -> ptr , (unsigned )nc -> slen );
420+ pj_md5_update (& ctx , (const pj_uint8_t * )":" , 1 );
421+ pj_md5_update (& ctx , (const pj_uint8_t * )cnonce -> ptr , (unsigned )cnonce -> slen );
422+ pj_md5_update (& ctx , (const pj_uint8_t * )":" , 1 );
423+ pj_md5_update (& ctx , (const pj_uint8_t * )qop -> ptr , (unsigned )qop -> slen );
424+ }
425+ pj_md5_update (& ctx , (const pj_uint8_t * )":" , 1 );
426+ pj_md5_update (& ctx , (const pj_uint8_t * )ha2 , (unsigned )digest_strlen );
427+ pj_md5_final (& ctx , digest );
428+ dig_len = digest_len ;
429+ } else {
430+ mdctx = EVP_MD_CTX_new ();
431+ EVP_DigestInit_ex (mdctx , md , NULL );
432+ EVP_DigestUpdate (mdctx , ha1 , digest_strlen );
362433 EVP_DigestUpdate (mdctx , ":" , 1 );
363- EVP_DigestUpdate (mdctx , cnonce -> ptr , cnonce -> slen );
434+ EVP_DigestUpdate (mdctx , nonce -> ptr , nonce -> slen );
435+ if (qop && qop -> slen != 0 ) {
436+ EVP_DigestUpdate (mdctx , ":" , 1 );
437+ EVP_DigestUpdate (mdctx , nc -> ptr , nc -> slen );
438+ EVP_DigestUpdate (mdctx , ":" , 1 );
439+ EVP_DigestUpdate (mdctx , cnonce -> ptr , cnonce -> slen );
440+ EVP_DigestUpdate (mdctx , ":" , 1 );
441+ EVP_DigestUpdate (mdctx , qop -> ptr , qop -> slen );
442+ }
364443 EVP_DigestUpdate (mdctx , ":" , 1 );
365- EVP_DigestUpdate (mdctx , qop -> ptr , qop -> slen );
444+ EVP_DigestUpdate (mdctx , ha2 , digest_strlen );
445+ EVP_DigestFinal_ex (mdctx , digest , & dig_len );
446+ EVP_MD_CTX_free (mdctx );
366447 }
367- EVP_DigestUpdate (mdctx , ":" , 1 );
368- EVP_DigestUpdate (mdctx , ha2 , digest_strlen );
369-
370- EVP_DigestFinal_ex (mdctx , digest , & dig_len );
371- EVP_MD_CTX_free (mdctx );
372448
373449 /* Convert digest to string and store in chal->response. */
374450 result -> slen = digest_strlen ;
@@ -488,7 +564,10 @@ PJ_DEF(pj_bool_t) pjsip_auth_is_algorithm_supported(
488564#ifdef HAVE_NO_OPENSSL
489565 return (algorithm_type == PJSIP_AUTH_ALGORITHM_MD5 );
490566#else
491- {
567+ /* For MD5, allow support even if OpenSSL disables it; we'll fallback. */
568+ if (algorithm_type == PJSIP_AUTH_ALGORITHM_MD5 ) {
569+ return PJ_TRUE ;
570+ } else {
492571 const EVP_MD * md ;
493572 md = EVP_get_digestbyname (algorithm -> openssl_name );
494573 if (md == NULL ) {
@@ -1762,4 +1841,3 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_reinit_req( pjsip_auth_clt_sess *sess,
17621841 return PJ_SUCCESS ;
17631842
17641843}
1765-
0 commit comments