diff --git a/include/re_sha.h b/include/re_sha.h index 8fdd632cd..ff5fc87f8 100644 --- a/include/re_sha.h +++ b/include/re_sha.h @@ -32,3 +32,12 @@ void SHA1_Update(SHA1_CTX* context, const void *p, size_t len); void SHA1_Final(uint8_t digest[SHA1_DIGEST_SIZE], SHA1_CTX* context); #endif + +/** SHA256 values */ +enum { + SHA256_SIZE = 32, /**< Bytes in SHA256 hash */ + SHA256_STR_SIZE = 2*SHA256_SIZE + 1 /**< Bytes in SHA256 string */ +}; + +void sha256(const uint8_t *d, size_t n, uint8_t *md); +int sha256_printf(uint8_t *md, const char *fmt, ...); diff --git a/include/re_sip.h b/include/re_sip.h index fd2094d4e..a56221f1b 100644 --- a/include/re_sip.h +++ b/include/re_sip.h @@ -247,6 +247,7 @@ typedef int(sip_auth_h)(char **username, char **password, const char *realm, typedef bool(sip_hdr_h)(const struct sip_hdr *hdr, const struct sip_msg *msg, void *arg); typedef void(sip_keepalive_h)(int err, void *arg); +typedef int(digest_printf_h)(uint8_t *md, const char *fmt, ...); #define LIBRE_HAVE_SIPTRACE 1 typedef void(sip_trace_h)(bool tx, enum sip_transp tp, diff --git a/src/sha/mod.mk b/src/sha/mod.mk index c40fdff08..0be3a312b 100644 --- a/src/sha/mod.mk +++ b/src/sha/mod.mk @@ -6,4 +6,7 @@ ifeq ($(USE_OPENSSL),) SRCS += sha/sha1.c +else +SRCS += sha/wrap.c endif + diff --git a/src/sha/wrap.c b/src/sha/wrap.c new file mode 100644 index 000000000..5fa981241 --- /dev/null +++ b/src/sha/wrap.c @@ -0,0 +1,55 @@ +/** + * @file wrap.c SHA256 wrappers + * + */ +#ifdef USE_OPENSSL +#include +#include +#include +#include +#include +#include +#include + +/** + * Calculate the SHA256 hash from a buffer + * + * @param d Data buffer (input) + * @param n Number of input bytes + * @param md Calculated SHA256 hash (output) + */ +void sha256(const uint8_t *d, size_t n, uint8_t *md) +{ + (void)SHA256(d, n, md); +} + + +/** + * Calculate the SHA256 hash from a formatted string + * + * @param md Calculated SHA256 hash + * @param fmt Formatted string + * + * @return 0 if success, otherwise errorcode + */ +int sha256_printf(uint8_t *md, const char *fmt, ...) +{ + struct mbuf mb; + va_list ap; + int err; + + mbuf_init(&mb); + + va_start(ap, fmt); + err = mbuf_vprintf(&mb, fmt, ap); + va_end(ap); + + if (!err) + sha256(mb.buf, mb.end, md); + + mbuf_reset(&mb); + + return err; +} + +#endif diff --git a/src/sip/auth.c b/src/sip/auth.c index a23f995da..8b62dd0b9 100644 --- a/src/sip/auth.c +++ b/src/sip/auth.c @@ -13,12 +13,16 @@ #include #include #include +#include #include #include #include #include #include "sip.h" +#define DEBUG_MODULE "sip_auth" +#define DEBUG_LEVEL 5 +#include struct sip_auth { struct list realml; @@ -37,6 +41,7 @@ struct realm { char *opaque; char *user; char *pass; + char *algorithm; uint32_t nc; enum sip_hdrid hdr; }; @@ -64,6 +69,7 @@ static void realm_destructor(void *arg) mem_deref(realm->opaque); mem_deref(realm->user); mem_deref(realm->pass); + mem_deref(realm->algorithm); } @@ -81,30 +87,54 @@ static void auth_destructor(void *arg) static int mkdigest(uint8_t *digest, const struct realm *realm, const char *met, const char *uri, uint64_t cnonce) { - uint8_t ha1[MD5_SIZE], ha2[MD5_SIZE]; + uint8_t *ha1, *ha2; + int h_size; int err; + digest_printf_h *digest_printf; + bool use_sha256 = str_casecmp(realm->algorithm, "sha-256") == 0; + +#ifndef USE_OPENSSL + if (use_sha256) { + DEBUG_WARNING("SHA2 digest only supported " + "when compiled with OpenSSL\n"); + return 1; + } +#endif + h_size = use_sha256 ? SHA256_SIZE : MD5_SIZE; + ha1 = mem_zalloc(h_size, NULL); + ha2 = mem_zalloc(h_size, NULL); - err = md5_printf(ha1, "%s:%s:%s", + if (use_sha256) + digest_printf = &sha256_printf; + else + digest_printf = &md5_printf; + err = digest_printf(ha1, "%s:%s:%s", realm->user, realm->realm, realm->pass); + if (err) - return err; + goto out; - err = md5_printf(ha2, "%s:%s", met, uri); + err = digest_printf(ha2, "%s:%s", met, uri); if (err) - return err; + goto out; + DEBUG_INFO("mkdigest algorithm: %s\n", realm->algorithm); if (realm->qop) - return md5_printf(digest, "%w:%s:%08x:%016llx:auth:%w", - ha1, sizeof(ha1), + err = digest_printf(digest, "%w:%s:%08x:%016llx:auth:%w", + ha1, h_size, realm->nonce, realm->nc, cnonce, - ha2, sizeof(ha2)); + ha2, h_size); else - return md5_printf(digest, "%w:%s:%w", - ha1, sizeof(ha1), + err = digest_printf(digest, "%w:%s:%w", + ha1, h_size, realm->nonce, - ha2, sizeof(ha2)); + ha2, h_size); +out: + mem_deref(ha1); + mem_deref(ha2); + return err; } @@ -135,11 +165,19 @@ static bool auth_handler(const struct sip_hdr *hdr, const struct sip_msg *msg, goto out; } - if (pl_isset(&ch.algorithm) && pl_strcasecmp(&ch.algorithm, "md5")) { + if (pl_isset(&ch.algorithm) && pl_strcasecmp(&ch.algorithm, "md5") && + pl_strcasecmp(&ch.algorithm, "sha-256")) { err = ENOSYS; goto out; } - +#ifndef USE_OPENSSL + if (pl_strcasecmp(&ch.algorithm, "sha-256") == 0) { + DEBUG_WARNING("SHA2 digest only supported " + "when compiled with OpenSSL\n"); + err = ENOSYS; + goto out; + } +#endif realm = list_ledata(list_apply(&auth->realml, true, cmp_handler, &ch.realm)); if (!realm) { @@ -155,6 +193,10 @@ static bool auth_handler(const struct sip_hdr *hdr, const struct sip_msg *msg, if (err) goto out; + err = pl_strdup(&realm->algorithm, &ch.algorithm); + if (err) + goto out; + err = auth->authh(&realm->user, &realm->pass, realm->realm, auth->arg); if (err) @@ -169,6 +211,7 @@ static bool auth_handler(const struct sip_hdr *hdr, const struct sip_msg *msg, realm->nonce = mem_deref(realm->nonce); realm->qop = mem_deref(realm->qop); realm->opaque = mem_deref(realm->opaque); + realm->algorithm = mem_deref(realm->algorithm); } realm->hdr = hdr->id; @@ -231,11 +274,25 @@ int sip_auth_encode(struct mbuf *mb, struct sip_auth *auth, const char *met, const uint64_t cnonce = rand_u64(); struct realm *realm = le->data; - uint8_t digest[MD5_SIZE]; + bool use_sha256; + uint8_t *digest; + int d_size; + use_sha256 = str_casecmp(realm->algorithm, "sha-256") == 0; +#ifndef USE_OPENSSL + if (use_sha256) { + DEBUG_WARNING("SHA2 digest only supported " + "when compiled with OpenSSL\n"); + break; + } +#endif + d_size = use_sha256 ? SHA256_SIZE : MD5_SIZE; + digest = mem_zalloc(d_size, NULL); err = mkdigest(digest, realm, met, uri, cnonce); - if (err) + if (err) { + mem_deref(digest); break; + } switch (realm->hdr) { @@ -256,7 +313,7 @@ int sip_auth_encode(struct mbuf *mb, struct sip_auth *auth, const char *met, err |= mbuf_printf(mb, ", nonce=\"%s\"", realm->nonce); err |= mbuf_printf(mb, ", uri=\"%s\"", uri); err |= mbuf_printf(mb, ", response=\"%w\"", - digest, sizeof(digest)); + digest, d_size); if (realm->opaque) err |= mbuf_printf(mb, ", opaque=\"%s\"", @@ -270,8 +327,9 @@ int sip_auth_encode(struct mbuf *mb, struct sip_auth *auth, const char *met, ++realm->nc; - err |= mbuf_write_str(mb, ", algorithm=MD5"); + err |= mbuf_printf(mb, ", algorithm=%s", realm->algorithm); err |= mbuf_write_str(mb, "\r\n"); + mem_deref(digest); if (err) break; }