HardenedBSD/contrib/ntp/libntp/a_md5encrypt.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

290 lines
6.8 KiB
C
Raw Normal View History

1999-12-09 14:01:21 +01:00
/*
* digest support for NTP, MD5 and with OpenSSL more
1999-12-09 14:01:21 +01:00
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
2004-07-20 17:01:56 +02:00
#include "ntp_fp.h"
1999-12-09 14:01:21 +01:00
#include "ntp_string.h"
#include "ntp_stdlib.h"
2004-07-20 17:01:56 +02:00
#include "ntp.h"
2016-04-27 07:37:54 +02:00
#include "isc/string.h"
2018-02-28 07:23:12 +01:00
typedef struct {
const void * buf;
size_t len;
} robuffT;
typedef struct {
void * buf;
size_t len;
} rwbuffT;
2018-08-20 08:07:33 +02:00
#if defined(OPENSSL) && defined(ENABLE_CMAC)
2018-02-28 07:23:12 +01:00
static size_t
cmac_ctx_size(
2023-06-06 14:26:44 +02:00
CMAC_CTX * ctx
)
2018-02-28 07:23:12 +01:00
{
size_t mlen = 0;
if (ctx) {
EVP_CIPHER_CTX * cctx;
if (NULL != (cctx = CMAC_CTX_get0_cipher_ctx (ctx)))
mlen = EVP_CIPHER_CTX_block_size(cctx);
}
return mlen;
}
2023-06-06 14:26:44 +02:00
#endif /* OPENSSL && ENABLE_CMAC */
2018-02-28 07:23:12 +01:00
2024-05-10 17:15:56 +02:00
/*
* Allocate and initialize a digest context. As a speed optimization,
* take an idea from ntpsec and cache the context to avoid malloc/free
* overhead in time-critical paths. ntpsec also caches the algorithms
* with each key.
* This is not thread-safe, but that is
* not a problem at present.
*/
static EVP_MD_CTX *
get_md_ctx(
int nid
)
{
#ifndef OPENSSL
static MD5_CTX md5_ctx;
DEBUG_INSIST(NID_md5 == nid);
MD5Init(&md5_ctx);
return &md5_ctx;
#else
if (!EVP_DigestInit(digest_ctx, EVP_get_digestbynid(nid))) {
msyslog(LOG_ERR, "%s init failed", OBJ_nid2sn(nid));
return NULL;
}
return digest_ctx;
#endif /* OPENSSL */
}
2018-02-28 07:23:12 +01:00
static size_t
make_mac(
const rwbuffT * digest,
int ktype,
const robuffT * key,
2023-06-06 14:26:44 +02:00
const robuffT * msg
)
2018-02-28 07:23:12 +01:00
{
/*
* Compute digest of key concatenated with packet. Note: the
* key type and digest type have been verified when the key
* was created.
*/
size_t retlen = 0;
2018-02-28 07:23:12 +01:00
#ifdef OPENSSL
2018-02-28 07:23:12 +01:00
INIT_SSL();
/* Check if CMAC key type specific code required */
2018-08-20 08:07:33 +02:00
# ifdef ENABLE_CMAC
2018-02-28 07:23:12 +01:00
if (ktype == NID_cmac) {
CMAC_CTX * ctx = NULL;
void const * keyptr = key->buf;
u_char keybuf[AES_128_KEY_SIZE];
/* adjust key size (zero padded buffer) if necessary */
if (AES_128_KEY_SIZE > key->len) {
memcpy(keybuf, keyptr, key->len);
2023-06-06 14:26:44 +02:00
zero_mem((keybuf + key->len),
(AES_128_KEY_SIZE - key->len));
2018-02-28 07:23:12 +01:00
keyptr = keybuf;
}
2018-02-28 07:23:12 +01:00
if (NULL == (ctx = CMAC_CTX_new())) {
msyslog(LOG_ERR, "MAC encrypt: CMAC %s CTX new failed.", CMAC);
goto cmac_fail;
}
if (!CMAC_Init(ctx, keyptr, AES_128_KEY_SIZE, EVP_aes_128_cbc(), NULL)) {
msyslog(LOG_ERR, "MAC encrypt: CMAC %s Init failed.", CMAC);
goto cmac_fail;
}
if (cmac_ctx_size(ctx) > digest->len) {
msyslog(LOG_ERR, "MAC encrypt: CMAC %s buf too small.", CMAC);
goto cmac_fail;
}
if (!CMAC_Update(ctx, msg->buf, msg->len)) {
msyslog(LOG_ERR, "MAC encrypt: CMAC %s Update failed.", CMAC);
goto cmac_fail;
}
if (!CMAC_Final(ctx, digest->buf, &retlen)) {
msyslog(LOG_ERR, "MAC encrypt: CMAC %s Final failed.", CMAC);
retlen = 0;
}
cmac_fail:
if (ctx)
CMAC_CTX_free(ctx);
2018-02-28 07:23:12 +01:00
}
2018-08-20 08:07:33 +02:00
else
2024-05-10 17:15:56 +02:00
# endif /* ENABLE_CMAC */
2018-08-20 08:07:33 +02:00
{ /* generic MAC handling */
2024-05-10 17:15:56 +02:00
EVP_MD_CTX * ctx;
2018-02-28 07:23:12 +01:00
u_int uilen = 0;
2024-05-10 17:15:56 +02:00
ctx = get_md_ctx(ktype);
if (NULL == ctx) {
2018-02-28 07:23:12 +01:00
goto mac_fail;
}
if ((size_t)EVP_MD_CTX_size(ctx) > digest->len) {
msyslog(LOG_ERR, "MAC encrypt: MAC %s buf too small.",
OBJ_nid2sn(ktype));
goto mac_fail;
}
if (!EVP_DigestUpdate(ctx, key->buf, (u_int)key->len)) {
msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update key failed.",
OBJ_nid2sn(ktype));
goto mac_fail;
}
if (!EVP_DigestUpdate(ctx, msg->buf, (u_int)msg->len)) {
msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update data failed.",
OBJ_nid2sn(ktype));
goto mac_fail;
}
if (!EVP_DigestFinal(ctx, digest->buf, &uilen)) {
msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Final failed.",
OBJ_nid2sn(ktype));
uilen = 0;
}
mac_fail:
retlen = (size_t)uilen;
}
#else /* !OPENSSL follows */
2024-05-10 17:15:56 +02:00
if (NID_md5 == ktype) {
EVP_MD_CTX * ctx;
2018-02-28 07:23:12 +01:00
2024-05-10 17:15:56 +02:00
ctx = get_md_ctx(ktype);
if (digest->len < MD5_LENGTH) {
2018-02-28 07:23:12 +01:00
msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 buf too small.");
2024-05-10 17:15:56 +02:00
} else {
MD5Init(ctx);
MD5Update(ctx, (const void *)key->buf, key->len);
MD5Update(ctx, (const void *)msg->buf, msg->len);
MD5Final(digest->buf, ctx);
retlen = MD5_LENGTH;
2018-02-28 07:23:12 +01:00
}
2024-05-10 17:15:56 +02:00
} else {
msyslog(LOG_ERR, "MAC encrypt: invalid key type %d", ktype);
2018-02-28 07:23:12 +01:00
}
2018-02-28 07:23:12 +01:00
#endif /* !OPENSSL */
return retlen;
}
1999-12-09 14:01:21 +01:00
/*
* MD5authencrypt - generate message digest
1999-12-09 14:01:21 +01:00
*
2024-05-10 17:15:56 +02:00
* Returns 0 on failure or length of MAC including key ID.
1999-12-09 14:01:21 +01:00
*/
2016-01-08 09:06:14 +01:00
size_t
1999-12-09 14:01:21 +01:00
MD5authencrypt(
2016-01-08 09:06:14 +01:00
int type, /* hash algorithm */
const u_char * key, /* key pointer */
2018-02-28 07:23:12 +01:00
size_t klen, /* key length */
2016-01-08 09:06:14 +01:00
u_int32 * pkt, /* packet pointer */
size_t length /* packet length */
1999-12-09 14:01:21 +01:00
)
{
u_char digest[EVP_MAX_MD_SIZE];
2018-02-28 07:23:12 +01:00
rwbuffT digb = { digest, sizeof(digest) };
robuffT keyb = { key, klen };
robuffT msgb = { pkt, length };
2024-05-10 17:15:56 +02:00
size_t dlen;
1999-12-09 14:01:21 +01:00
2018-02-28 07:23:12 +01:00
dlen = make_mac(&digb, type, &keyb, &msgb);
2024-05-10 17:15:56 +02:00
if (0 == dlen) {
return 0;
}
memcpy((u_char *)pkt + length + KEY_MAC_LEN, digest,
min(dlen, MAX_MDG_LEN));
2018-02-28 07:23:12 +01:00
return (dlen + KEY_MAC_LEN);
1999-12-09 14:01:21 +01:00
}
/*
* MD5authdecrypt - verify MD5 message authenticator
*
* Returns one if digest valid, zero if invalid.
1999-12-09 14:01:21 +01:00
*/
int
MD5authdecrypt(
2016-01-08 09:06:14 +01:00
int type, /* hash algorithm */
const u_char * key, /* key pointer */
2018-02-28 07:23:12 +01:00
size_t klen, /* key length */
2016-01-08 09:06:14 +01:00
u_int32 * pkt, /* packet pointer */
size_t length, /* packet length */
size_t size, /* MAC size */
keyid_t keyno /* key id (for err log) */
1999-12-09 14:01:21 +01:00
)
{
u_char digest[EVP_MAX_MD_SIZE];
2018-02-28 07:23:12 +01:00
rwbuffT digb = { digest, sizeof(digest) };
robuffT keyb = { key, klen };
robuffT msgb = { pkt, length };
2018-02-28 07:23:12 +01:00
size_t dlen = 0;
1999-12-09 14:01:21 +01:00
2018-02-28 07:23:12 +01:00
dlen = make_mac(&digb, type, &keyb, &msgb);
2024-05-10 17:15:56 +02:00
if (0 == dlen || size != dlen + KEY_MAC_LEN) {
msyslog(LOG_ERR,
2024-05-10 17:15:56 +02:00
"MAC decrypt: MAC length error: %u not %u for key %u",
(u_int)size, (u_int)(dlen + KEY_MAC_LEN), keyno);
return FALSE;
}
2018-02-28 07:23:12 +01:00
return !isc_tsmemcmp(digest,
(u_char *)pkt + length + KEY_MAC_LEN, dlen);
2004-07-20 17:01:56 +02:00
}
/*
* Calculate the reference id from the address. If it is an IPv4
* address, use it as is. If it is an IPv6 address, do a md5 on
* it and use the bottom 4 bytes.
2024-05-10 17:15:56 +02:00
* The result is in network byte order for IPv4 addreseses. For
* IPv6, ntpd long differed in the hash calculated on big-endian
* vs. little-endian because the first four bytes of the MD5 hash
* were used as a u_int32 without any byte swapping. This broke
* the refid-based loop detection between mixed-endian systems.
* In order to preserve behavior on the more-common little-endian
* systems, the hash is now byte-swapped on big-endian systems to
* match the little-endian hash. This is ugly but it seems better
* than changing the IPv6 refid calculation on the more-common
* systems.
* This is not thread safe, not a problem so far.
2004-07-20 17:01:56 +02:00
*/
u_int32
addr2refid(sockaddr_u *addr)
2004-07-20 17:01:56 +02:00
{
2024-05-10 17:15:56 +02:00
static MD5_CTX md5_ctx;
union u_tag {
u_char digest[MD5_DIGEST_LENGTH];
u_int32 addr_refid;
} u;
2004-07-20 17:01:56 +02:00
2024-05-10 17:15:56 +02:00
if (IS_IPV4(addr)) {
return (NSRCADR(addr));
}
2024-05-10 17:15:56 +02:00
/* MD5 is not used for authentication here. */
MD5Init(&md5_ctx);
MD5Update(&md5_ctx, (void *)&SOCK_ADDR6(addr), sizeof(SOCK_ADDR6(addr)));
MD5Final(u.digest, &md5_ctx);
#ifdef WORDS_BIGENDIAN
u.addr_refid = BYTESWAP32(u.addr_refid);
#endif
return u.addr_refid;
1999-12-09 14:01:21 +01:00
}