-
Notifications
You must be signed in to change notification settings - Fork 801
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add full support for SHA-256 and SHA-512-256 digest algorithms #4118
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,12 +42,66 @@ PJ_BEGIN_DECL | |
* @{ | ||
*/ | ||
|
||
/** Length of digest MD5 string. */ | ||
/** | ||
* Length of digest MD5 string. | ||
* \deprecated Use #pjsip_auth_algorithm::digest_str_length instead. | ||
*/ | ||
#define PJSIP_MD5STRLEN 32 | ||
|
||
/** Length of digest SHA256 string. */ | ||
/** | ||
* Length of digest SHA256 string. | ||
* \deprecated Use #pjsip_auth_algorithm::digest_str_length instead. | ||
*/ | ||
#define PJSIP_SHA256STRLEN 64 | ||
|
||
/** | ||
* The length of the buffer needed to contain the largest | ||
* supported algorithm's digest. | ||
*/ | ||
#define PJSIP_AUTH_MAX_DIGEST_BUFFER_LENGTH 64 | ||
|
||
/** | ||
* Digest Algorithm Types. | ||
* \warning These entries must remain in order with | ||
* no gaps and with _NOT_SET = 0 and _COUNT as the last entry. | ||
* | ||
* The MD5, SHA-256, and SHA-512/256 algorithms are described | ||
* in RFC 7616 and RFC 8760. | ||
* The AKA algorithms are described in RFC 3310 and RFC 4169 | ||
* and 3GPP TS 33.203. | ||
*/ | ||
typedef enum pjsip_auth_algorithm_type | ||
{ | ||
PJSIP_AUTH_ALGORITHM_NOT_SET = 0, /**< Algorithm not set. */ | ||
PJSIP_AUTH_ALGORITHM_MD5, /**< MD5 algorithm. */ | ||
PJSIP_AUTH_ALGORITHM_SHA256, /**< SHA-256 algorithm. */ | ||
PJSIP_AUTH_ALGORITHM_SHA512_256, /**< SHA-512/256 algorithm */ | ||
PJSIP_AUTH_ALGORITHM_AKAV1_MD5, /**< AKA v1 with MD5 algorithm. */ | ||
PJSIP_AUTH_ALGORITHM_AKAV2_MD5, /**< AKA v2 with MD5 algorithm. */ | ||
PJSIP_AUTH_ALGORITHM_COUNT, /**< Number of algorithms. */ | ||
} pjsip_auth_algorithm_type; | ||
|
||
|
||
/** | ||
* Authentication Digest Algorithm | ||
* | ||
* This structure describes a digest algorithm used in | ||
* SIP authentication. | ||
* | ||
*/ | ||
typedef struct pjsip_auth_algorithm | ||
{ | ||
pjsip_auth_algorithm_type algorithm_type; /**< Digest algorithm type */ | ||
pj_str_t iana_name; /**< IANA/RFC name used in | ||
SIP headers */ | ||
const char *openssl_name; /**< The name used by OpenSSL's | ||
EVP_get_digestbyname() */ | ||
unsigned digest_length; /**< Length of the raw digest | ||
in bytes */ | ||
unsigned digest_str_length; /**< Length of the digest HEX | ||
representation */ | ||
} pjsip_auth_algorithm; | ||
|
||
|
||
/** Type of data in the credential information in #pjsip_cred_info. */ | ||
typedef enum pjsip_cred_data_type | ||
|
@@ -59,6 +113,13 @@ typedef enum pjsip_cred_data_type | |
|
||
} pjsip_cred_data_type; | ||
|
||
#define PJSIP_CRED_DATA_PASSWD_MASK 0x000F | ||
#define PJSIP_CRED_DATA_EXT_MASK 0x00F0 | ||
|
||
#define PJSIP_CRED_DATA_IS_AKA(cred) (((cred)->data_type & PJSIP_CRED_DATA_EXT_MASK) == PJSIP_CRED_DATA_EXT_AKA) | ||
#define PJSIP_CRED_DATA_IS_PASSWD(cred) (((cred)->data_type & PJSIP_CRED_DATA_PASSWD_MASK) == PJSIP_CRED_DATA_PLAIN_PASSWD) | ||
#define PJSIP_CRED_DATA_IS_DIGEST(cred) (((cred)->data_type & PJSIP_CRED_DATA_PASSWD_MASK) == PJSIP_CRED_DATA_DIGEST) | ||
|
||
/** Authentication's quality of protection (qop) type. */ | ||
typedef enum pjsip_auth_qop_type | ||
{ | ||
|
@@ -102,11 +163,14 @@ typedef pj_status_t (*pjsip_cred_cb)(pj_pool_t *pool, | |
/** | ||
* This structure describes credential information. | ||
* A credential information is a static, persistent information that identifies | ||
* username and password required to authorize to a specific realm. | ||
* credentials required to authorize to a specific realm. | ||
* | ||
* Note that since PJSIP 0.7.0.1, it is possible to make a credential that is | ||
* valid for any realms, by setting the realm to star/wildcard character, | ||
* i.e. realm = pj_str("*");. | ||
* | ||
* You should always fill this structure with zeros using PJ_POOL_ZALLOC_T() | ||
* or pj_bzero() before setting any fields. | ||
*/ | ||
struct pjsip_cred_info | ||
{ | ||
|
@@ -115,9 +179,15 @@ struct pjsip_cred_info | |
challenges. */ | ||
pj_str_t scheme; /**< Scheme (e.g. "digest"). */ | ||
pj_str_t username; /**< User name. */ | ||
int data_type; /**< Type of data (0 for plaintext passwd). */ | ||
int data_type; /**< Type of data \ref pjsip_cred_data_type */ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because that's the way it was historically and I didn't want to change the signature with this patch. |
||
pj_str_t data; /**< The data, which can be a plaintext | ||
password or a hashed digest. */ | ||
/** | ||
* If the data_type is #PJSIP_CRED_DATA_DIGEST and the digest algorithm | ||
* used is not MD5 (the default), then this field MUST be set to the | ||
* appropriate digest algorithm type. | ||
*/ | ||
pjsip_auth_algorithm_type algorithm_type; /**< Digest algorithm type */ | ||
|
||
/** Extended data */ | ||
union { | ||
|
@@ -182,7 +252,8 @@ typedef struct pjsip_cached_auth | |
pjsip_cached_auth_hdr cached_hdr;/**< List of cached header for | ||
each method. */ | ||
#endif | ||
|
||
pjsip_auth_algorithm_type challenge_algorithm_type; /**< Challenge | ||
algorithm */ | ||
} pjsip_cached_auth; | ||
|
||
|
||
|
@@ -208,6 +279,45 @@ typedef struct pjsip_auth_clt_pref | |
} pjsip_auth_clt_pref; | ||
|
||
|
||
/** | ||
* Get a pjsip_auth_algorithm structure by type. | ||
* | ||
* @param algorithm_type The algorithm type | ||
* | ||
* @return A pointer to a pjsip_auth_algorithm structure | ||
* or NULL if not found. | ||
*/ | ||
PJ_DECL(const pjsip_auth_algorithm *) pjsip_auth_get_algorithm_by_type( | ||
pjsip_auth_algorithm_type algorithm_type); | ||
|
||
|
||
/** | ||
* Get a pjsip_auth_algorithm by IANA name. | ||
* | ||
* @param iana_name The IANA name (MD5, SHA-256, SHA-512-256) | ||
* | ||
* @return A pointer to a pjsip_auth_algorithm structure | ||
* or NULL if not found. | ||
*/ | ||
PJ_DECL(const pjsip_auth_algorithm *) pjsip_auth_get_algorithm_by_iana_name( | ||
const pj_str_t *iana_name); | ||
|
||
|
||
/** | ||
* Check if a digest algorithm is supported. | ||
* Algorithms that require support from OpenSSL will be checked | ||
* at runtime to determine if they are actually available in | ||
* the current version of OpenSSL. | ||
* | ||
* @param algorithm_type The algorithm type | ||
* | ||
* @return PJ_TRUE if the algorithm is supported, | ||
* PJ_FALSE otherwise. | ||
*/ | ||
PJ_DECL(pj_bool_t) pjsip_auth_is_algorithm_supported( | ||
pjsip_auth_algorithm_type algorithm_type); | ||
|
||
|
||
/** | ||
* Duplicate a client authentication preference setting. | ||
* | ||
|
@@ -284,10 +394,12 @@ typedef pj_status_t pjsip_auth_lookup_cred( pj_pool_t *pool, | |
*/ | ||
typedef struct pjsip_auth_lookup_cred_param | ||
{ | ||
pj_str_t realm; /**< Realm to find the account. */ | ||
pj_str_t acc_name; /**< Account name to look for. */ | ||
pjsip_rx_data *rdata; /**< Incoming request to be authenticated. */ | ||
|
||
pj_str_t realm; /**< Realm to find the account. */ | ||
pj_str_t acc_name; /**< Account name to look for. */ | ||
pjsip_rx_data *rdata; /**< Incoming request to be | ||
authenticated. */ | ||
pjsip_authorization_hdr *auth_hdr; /**< Authorization header to be | ||
authenticated. */ | ||
} pjsip_auth_lookup_cred_param; | ||
|
||
|
||
|
@@ -549,7 +661,8 @@ PJ_DECL(pj_status_t) pjsip_auth_srv_verify( pjsip_auth_srv *auth_srv, | |
* Add authentication challenge headers to the outgoing response in tdata. | ||
* Application may specify its customized nonce and opaque for the challenge, | ||
* or can leave the value to NULL to make the function fills them in with | ||
* random characters. | ||
* random characters. The digest algorithm defaults to MD5. If you need | ||
* to specify a different algorithm, use #pjsip_auth_srv_challenge2. | ||
* | ||
* @param auth_srv The server authentication structure. | ||
* @param qop Optional qop value. | ||
|
@@ -569,9 +682,43 @@ PJ_DECL(pj_status_t) pjsip_auth_srv_challenge( pjsip_auth_srv *auth_srv, | |
pjsip_tx_data *tdata); | ||
|
||
/** | ||
* Helper function to create MD5 digest out of the specified | ||
* Add authentication challenge headers to the outgoing response in tdata. | ||
* Application may specify its customized nonce and opaque for the challenge, | ||
* or can leave the value to NULL to make the function fills them in with | ||
* random characters. | ||
* Application must specify the algorithm to use. | ||
* | ||
* @param auth_srv The server authentication structure. | ||
* @param qop Optional qop value. | ||
* @param nonce Optional nonce value. | ||
* @param opaque Optional opaque value. | ||
* @param stale Stale indication. | ||
* @param tdata The outgoing response message. The response must have | ||
* 401 or 407 response code. | ||
* @param algorithm_type One of the #pjsip_auth_algorithm_type values. | ||
* | ||
* @return PJ_SUCCESS on success. | ||
*/ | ||
PJ_DECL(pj_status_t) pjsip_auth_srv_challenge2(pjsip_auth_srv *auth_srv, | ||
const pj_str_t *qop, | ||
const pj_str_t *nonce, | ||
const pj_str_t *opaque, | ||
pj_bool_t stale, | ||
pjsip_tx_data *tdata, | ||
const pjsip_auth_algorithm_type algorithm_type); | ||
|
||
/** | ||
* Helper function to create a digest out of the specified | ||
* parameters. | ||
* | ||
* \warning Because of ambiguities in the API, this function | ||
* should only be used for backward compatibility with the | ||
* MD5 digest algorithm. New code should use | ||
* #pjsip_auth_create_digest2 | ||
* | ||
* pjsip_cred_info::data_type must be #PJSIP_CRED_DATA_PLAIN_PASSWD | ||
* or #PJSIP_CRED_DATA_DIGEST. | ||
* | ||
* @param result String to store the response digest. This string | ||
* must have been preallocated by caller with the | ||
* buffer at least PJSIP_MD5STRLEN (32 bytes) in size. | ||
|
@@ -599,6 +746,9 @@ PJ_DECL(pj_status_t) pjsip_auth_create_digest(pj_str_t *result, | |
/** | ||
* Helper function to create SHA-256 digest out of the specified | ||
* parameters. | ||
* \deprecated Use #pjsip_auth_create_digest2 with | ||
* algorithm_type = #PJSIP_AUTH_ALGORITHM_SHA256. | ||
* | ||
* | ||
* @param result String to store the response digest. This string | ||
* must have been preallocated by caller with the | ||
|
@@ -614,7 +764,7 @@ PJ_DECL(pj_status_t) pjsip_auth_create_digest(pj_str_t *result, | |
* | ||
* @return PJ_SUCCESS on success. | ||
*/ | ||
PJ_DEF(pj_status_t) pjsip_auth_create_digestSHA256(pj_str_t* result, | ||
PJ_DECL(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, | ||
|
@@ -624,6 +774,56 @@ PJ_DEF(pj_status_t) pjsip_auth_create_digestSHA256(pj_str_t* result, | |
const pjsip_cred_info* cred_info, | ||
const pj_str_t* method); | ||
|
||
/** | ||
* Helper function to create a digest out of the specified | ||
* parameters. | ||
* | ||
* pjsip_cred_info::data_type must be #PJSIP_CRED_DATA_PLAIN_PASSWD | ||
* or #PJSIP_CRED_DATA_DIGEST. | ||
* | ||
* If pjsip_cred_info::data_type is #PJSIP_CRED_DATA_PLAIN_PASSWORD, | ||
* pjsip_cred_info::username + ":" + realm + ":" + pjsip_cred_info::data | ||
* will be hashed using the algorithm_type specified by the last | ||
* parameter passed to this function to create the "ha1" hash. | ||
* | ||
* If pjsip_cred_info::data_type is #PJSIP_CRED_DATA_DIGEST, | ||
* pjsip_cred_info::data must contain the value of | ||
* username + ":" + realm + ":" + password | ||
* pre-hashed with the algorithm specifed by pjsip_cred_info::algorithm_type | ||
* and will be used as the "ha1" hash directly. In this case | ||
* pjsip_cred_info::algorithm_type MUST match the algorithm_type | ||
* passed as the last parameter to this function. | ||
* | ||
* \note If left unset (0), pjsip_cred_info::algorithm_type will | ||
* default to #PJSIP_AUTH_ALGORITHM_MD5. | ||
* | ||
* @param result String to store the response digest. This string | ||
* must have been preallocated by the caller with the | ||
* buffer at least as large as the digest_str_length | ||
* member of the appropriate pjsip_auth_algorithm. | ||
* @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. | ||
* @param algorithm_type The hash algorithm to use. | ||
* | ||
* @return PJ_SUCCESS on success. | ||
*/ | ||
PJ_DECL(pj_status_t) pjsip_auth_create_digest2(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, | ||
const pjsip_auth_algorithm_type algorithm_type); | ||
|
||
/** | ||
* @} | ||
*/ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here and below I would use
pj_size_t
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Digest lengths will never need a size_t so why allocate an extra 4 bytes for each of them?