Skip to content

Commit bf41e86

Browse files
authored
Fix sip auth if OpenSSL MD5 is unavailable (#4603)
1 parent b518a39 commit bf41e86

File tree

1 file changed

+115
-37
lines changed

1 file changed

+115
-37
lines changed

pjsip/src/pjsip/sip_auth_client.c

Lines changed: 115 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,35 @@
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+
81110
const 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

Comments
 (0)