CVE-2022-24754 (C, published 2022-03-11T20:15Z)
Description: value: PJSIP is a free and open source multimedia communication library written in C language. In versions prior to and including 2.12 PJSIP there is a stack-buffer overflow vulnerability which only impacts PJSIP users who accept hashed digest credentials (credentials with data_type `PJSIP_CRED_DATA_DIGEST`). This issue has been patched in the master branch of the PJSIP repository and will be included with the next release. Users unable to upgrade need to check that the hashed digest data length must be equal to `PJSIP_MD5STRLEN` before passing to PJSIP.
Severity: HIGH (CVSS v3 base score: 9.8)
Weakness: CWE-120 \u2014 Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')
The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow.
Repository: https://github.com/pjsip/pjproject
Files changed:
pjsip/include/pjsip/sip_auth.h
pjsip/src/pjsip/sip_auth_aka.c
pjsip/src/pjsip/sip_auth_client.c
pjsip/src/pjsip/sip_auth_server.c
pjsip/src/pjsua-lib/pjsua_core.c
Commit message: Use PJ_ASSERT_RETURN() on pjsip_auth_create_digest() and pjsua_init_tpselector() (#3009)

* Use PJ_ASSERT_RETURN on pjsip_auth_create_digest

* Use PJ_ASSERT_RETURN on pjsua_init_tpselector()

* Fix incorrect check.

* Add return value to pjsip_auth_create_digest() and pjsip_auth_create_digestSHA256()

* Modification based on comments.

Vulnerable code:
PJ_DECL(void) pjsip_auth_create_digest(pj_str_t *result,
				       const pj_str_t *nonce,
				       const pj_str_t *nc,
				       const pj_str_t *cnonce,
				       const pj_str_t *qop,
				       const pj_str_t *uri,
				       const pj_str_t *realm,
				       const pjsip_cred_info *cred_info,
				       const pj_str_t *method);
    pj_status_t status;
	 * A normal MD5 authentication is requested. Fallbackt to the usual
	pjsip_auth_create_digest(&auth->response, &auth->nonce, &auth->nc,
				 &auth->cnonce, &auth->qop, &auth->uri,
				 &auth->realm, cred, method);
	return PJ_SUCCESS;
	pjsip_auth_create_digest(&auth->response, &chal->nonce, 
				 &auth->uri, &chal->realm, &aka_cred, method);
	pjsip_auth_create_digest(&auth->response, &chal->nonce, 
    return PJ_SUCCESS;
PJ_DEF(void) pjsip_auth_create_digest( pj_str_t *result,
				       const pj_str_t *nonce,
				       const pj_str_t *nc,
				       const pj_str_t *cnonce,
				       const pj_str_t *qop,
				       const pj_str_t *uri,
				       const pj_str_t *realm,
				       const pjsip_cred_info *cred_info,
				       const pj_str_t *method)
	pj_assert(cred_info->data.slen == 32);
PJ_DEF(void) pjsip_auth_create_digestSHA256(pj_str_t *result,
	pj_assert(cred_info->data.slen == 32);
		pjsip_auth_create_digestSHA256(
		pjsip_auth_create_digest( &cred->response, &cred->nonce, NULL,
					  NULL,  NULL, uri, &chal->realm,
					  cred_info, method);
		pjsip_auth_create_digestSHA256(
		pjsip_auth_create_digest( &cred->response, &cred->nonce,
					  &cred->nc, &cred->cnonce,
					  &pjsip_AUTH_STR, uri,
					  &chal->realm, cred_info,
					  method);
    return PJ_SUCCESS;
	pjsip_auth_create_digest(&digest, 
    pj_assert(tp_id >= 0 && tp_id < (int)PJ_ARRAY_SIZE(pjsua_var.tpdata));

Fixed code:
 *
 * @return		PJ_SUCCESS on success.
PJ_DECL(pj_status_t) pjsip_auth_create_digest(pj_str_t *result,
					      const pj_str_t *nonce,
					      const pj_str_t *nc,
					      const pj_str_t *cnonce,
					      const pj_str_t *qop,
					      const pj_str_t *uri,
					      const pj_str_t *realm,
					      const pjsip_cred_info *cred_info,
					      const pj_str_t *method);

/**
 * Helper function to create SHA-256 digest out of the specified 
 * parameters.
 *
 * @param result	String to store the response digest. This string
 *			must have been preallocated by caller with the 
 *			buffer at least PJSIP_SHA256STRLEN (64 bytes) in size.
 * @param nonce		Optional nonce.
 * @param nc		Nonce count.
 * @param cnonce	Optional cnonce.
 * @param qop		Optional qop.
 * @param uri		URI.
 * @param realm		Realm.
 * @param cred_info	Credential info.
 * @param method	SIP method.
 *
 * @return		PJ_SUCCESS on success. 
 */
PJ_DEF(pj_status_t) pjsip_auth_create_digestSHA256(pj_str_t* result,
					    const pj_str_t* nonce,
					    const pj_str_t* nc,
					    const pj_str_t* cnonce,
					    const pj_str_t* qop,
					    const pj_str_t* uri,
					    const pj_str_t* realm,
					    const pjsip_cred_info* cred_info,
					    const pj_str_t* method);
    pj_status_t status = PJ_SUCCESS;
	 * A normal MD5 authentication is requested. Fallback to the usual
	status = pjsip_auth_create_digest(&auth->response, &auth->nonce, 
			         &auth->nc, &auth->cnonce, &auth->qop, 
			         &auth->uri, &auth->realm, cred, method);

	return status;
	status = pjsip_auth_create_digest(&auth->response, &chal->nonce, 
				 &auth->uri, &chal->realm, &aka_cred, method);	
	status = pjsip_auth_create_digest(&auth->response, &chal->nonce, 
    return status;
PJ_DEF(pj_status_t) pjsip_auth_create_digest( pj_str_t *result,
					      const pj_str_t *nonce,
					      const pj_str_t *nc,
					      const pj_str_t *cnonce,
					      const pj_str_t *qop,
					      const pj_str_t *uri,
					      const pj_str_t *realm,
					      const pjsip_cred_info *cred_info,
					      const pj_str_t *method)
	if (cred_info->data.slen != 32) {
	    pj_assert(!"Invalid cred_info data length");
	    pj_bzero(result->ptr, result->slen);
	    result->slen = 0;
	    return PJ_EINVAL;
	}
	pj_bzero(result->ptr, result->slen);
	result->slen = 0;
	return PJ_EINVAL;
    return PJ_SUCCESS;
PJ_DEF(pj_status_t) pjsip_auth_create_digestSHA256(pj_str_t *result,
	if (cred_info->data.slen != 64) {
	    pj_assert(!"Invalid cred_info data length");
	    pj_bzero(result->ptr, result->slen);
	    result->slen = 0;
	    return PJ_EINVAL;
	}
	pj_bzero(result->ptr, result->slen);
	result->slen = 0;
	return PJ_EINVAL;
    return PJ_SUCCESS;
    pj_status_t status = PJ_SUCCESS;
		status = pjsip_auth_create_digestSHA256(
		status = pjsip_auth_create_digest( &cred->response, 
					  &cred->nonce, NULL, NULL, NULL, uri, 
					  &chal->realm, cred_info, method);
		status = pjsip_auth_create_digestSHA256(
		status = pjsip_auth_create_digest( &cred->response, 
					  &cred->nonce, &cred->nc, 
				          &cred->cnonce, &pjsip_AUTH_STR, 
					  uri, &chal->realm, 
					  cred_info, method);
    return status;
	pj_status_t status;
	status = pjsip_auth_create_digest(&digest, 
	if (status != PJ_SUCCESS)
	    return status;

    PJ_ASSERT_RETURN(tp_id >= 0 && 
		     tp_id < (int)PJ_ARRAY_SIZE(pjsua_var.tpdata), );