summaryrefslogtreecommitdiff
path: root/libntp/a_md5encrypt.c
diff options
context:
space:
mode:
Diffstat (limited to 'libntp/a_md5encrypt.c')
-rw-r--r--libntp/a_md5encrypt.c248
1 files changed, 198 insertions, 50 deletions
diff --git a/libntp/a_md5encrypt.c b/libntp/a_md5encrypt.c
index 7394d0d27b357..7dc7e7ecf40dd 100644
--- a/libntp/a_md5encrypt.c
+++ b/libntp/a_md5encrypt.c
@@ -11,6 +11,177 @@
#include "ntp.h"
#include "ntp_md5.h" /* provides OpenSSL digest API */
#include "isc/string.h"
+
+#ifdef OPENSSL
+# include "openssl/cmac.h"
+# define CMAC "AES128CMAC"
+# define AES_128_KEY_SIZE 16
+#endif
+
+typedef struct {
+ const void * buf;
+ size_t len;
+} robuffT;
+
+typedef struct {
+ void * buf;
+ size_t len;
+} rwbuffT;
+
+#ifdef OPENSSL
+static size_t
+cmac_ctx_size(
+ CMAC_CTX * ctx)
+{
+ 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;
+}
+#endif /*OPENSSL*/
+
+static size_t
+make_mac(
+ const rwbuffT * digest,
+ int ktype,
+ const robuffT * key,
+ const robuffT * msg)
+{
+ /*
+ * 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;
+
+#ifdef OPENSSL
+
+ INIT_SSL();
+
+ /* Check if CMAC key type specific code required */
+ 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);
+ memset((keybuf + key->len), 0,
+ (AES_128_KEY_SIZE - key->len));
+ keyptr = keybuf;
+ }
+
+ 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_cleanup(ctx);
+ }
+ else { /* generic MAC handling */
+ EVP_MD_CTX * ctx = EVP_MD_CTX_new();
+ u_int uilen = 0;
+
+ if ( ! ctx) {
+ msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest CTX new failed.",
+ OBJ_nid2sn(ktype));
+ goto mac_fail;
+ }
+
+ #ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
+ /* make sure MD5 is allowd */
+ EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+ #endif
+ /* [Bug 3457] DON'T use plain EVP_DigestInit! It would
+ * kill the flags! */
+ if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(ktype), NULL)) {
+ msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Init failed.",
+ OBJ_nid2sn(ktype));
+ 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;
+
+ if (ctx)
+ EVP_MD_CTX_free(ctx);
+ }
+
+#else /* !OPENSSL follows */
+
+ if (ktype == NID_md5)
+ {
+ EVP_MD_CTX * ctx = EVP_MD_CTX_new();
+ uint uilen = 0;
+
+ if (digest->len < 16) {
+ msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 buf too small.");
+ }
+ else if ( ! ctx) {
+ msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 Digest CTX new failed.");
+ }
+ else {
+ EVP_DigestInit(ctx, EVP_get_digestbynid(ktype));
+ EVP_DigestUpdate(ctx, key->buf, key->len);
+ EVP_DigestUpdate(ctx, msg->buf, msg->len);
+ EVP_DigestFinal(ctx, digest->buf, &uilen);
+ }
+ if (ctx)
+ EVP_MD_CTX_free(ctx);
+ retlen = (size_t)uilen;
+ }
+ else
+ {
+ msyslog(LOG_ERR, "MAC encrypt: invalid key type %d" , ktype);
+ }
+
+#endif /* !OPENSSL */
+
+ return retlen;
+}
+
+
/*
* MD5authencrypt - generate message digest
*
@@ -20,36 +191,23 @@ size_t
MD5authencrypt(
int type, /* hash algorithm */
const u_char * key, /* key pointer */
+ size_t klen, /* key length */
u_int32 * pkt, /* packet pointer */
size_t length /* packet length */
)
{
u_char digest[EVP_MAX_MD_SIZE];
- u_int len;
- EVP_MD_CTX *ctx;
+ rwbuffT digb = { digest, sizeof(digest) };
+ robuffT keyb = { key, klen };
+ robuffT msgb = { pkt, length };
+ size_t dlen = 0;
- /*
- * Compute digest of key concatenated with packet. Note: the
- * key type and digest type have been verified when the key
- * was creaded.
- */
- INIT_SSL();
- ctx = EVP_MD_CTX_new();
- if (!(ctx && EVP_DigestInit(ctx, EVP_get_digestbynid(type)))) {
- msyslog(LOG_ERR,
- "MAC encrypt: digest init failed");
- EVP_MD_CTX_free(ctx);
- return (0);
- }
- EVP_DigestUpdate(ctx, key, cache_secretsize);
- EVP_DigestUpdate(ctx, (u_char *)pkt, length);
- EVP_DigestFinal(ctx, digest, &len);
- EVP_MD_CTX_free(ctx);
+ dlen = make_mac(&digb, type, &keyb, &msgb);
/* If the MAC is longer than the MAX then truncate it. */
- if (len > MAX_MAC_LEN - 4)
- len = MAX_MAC_LEN - 4;
- memmove((u_char *)pkt + length + 4, digest, len);
- return (len + 4);
+ if (dlen > MAX_MDG_LEN)
+ dlen = MAX_MDG_LEN;
+ memcpy((u_char *)pkt + length + KEY_MAC_LEN, digest, dlen);
+ return (dlen + KEY_MAC_LEN);
}
@@ -62,41 +220,30 @@ int
MD5authdecrypt(
int type, /* hash algorithm */
const u_char * key, /* key pointer */
+ size_t klen, /* key length */
u_int32 * pkt, /* packet pointer */
size_t length, /* packet length */
size_t size /* MAC size */
)
{
u_char digest[EVP_MAX_MD_SIZE];
- u_int len;
- EVP_MD_CTX *ctx;
+ rwbuffT digb = { digest, sizeof(digest) };
+ robuffT keyb = { key, klen };
+ robuffT msgb = { pkt, length };
+ size_t dlen = 0;
- /*
- * Compute digest of key concatenated with packet. Note: the
- * key type and digest type have been verified when the key
- * was created.
- */
- INIT_SSL();
- ctx = EVP_MD_CTX_new();
- if (!(ctx && EVP_DigestInit(ctx, EVP_get_digestbynid(type)))) {
- msyslog(LOG_ERR,
- "MAC decrypt: digest init failed");
- EVP_MD_CTX_free(ctx);
- return (0);
- }
- EVP_DigestUpdate(ctx, key, cache_secretsize);
- EVP_DigestUpdate(ctx, (u_char *)pkt, length);
- EVP_DigestFinal(ctx, digest, &len);
- EVP_MD_CTX_free(ctx);
+ dlen = make_mac(&digb, type, &keyb, &msgb);
+
/* If the MAC is longer than the MAX then truncate it. */
- if (len > MAX_MAC_LEN - 4)
- len = MAX_MAC_LEN - 4;
- if (size != (size_t)len + 4) {
+ if (dlen > MAX_MDG_LEN)
+ dlen = MAX_MDG_LEN;
+ if (size != (size_t)dlen + KEY_MAC_LEN) {
msyslog(LOG_ERR,
"MAC decrypt: MAC length error");
return (0);
}
- return !isc_tsmemcmp(digest, (u_char *)pkt + length + 4, len);
+ return !isc_tsmemcmp(digest,
+ (u_char *)pkt + length + KEY_MAC_LEN, dlen);
}
/*
@@ -108,7 +255,7 @@ MD5authdecrypt(
u_int32
addr2refid(sockaddr_u *addr)
{
- u_char digest[20];
+ u_char digest[EVP_MAX_MD_SIZE];
u_int32 addr_refid;
EVP_MD_CTX *ctx;
u_int len;
@@ -119,11 +266,12 @@ addr2refid(sockaddr_u *addr)
INIT_SSL();
ctx = EVP_MD_CTX_new();
- EVP_MD_CTX_init(ctx);
-#ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
+# ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
/* MD5 is not used as a crypto hash here. */
EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
-#endif
+# endif
+ /* [Bug 3457] DON'T use plain EVP_DigestInit! It would kill the
+ * flags! */
if (!EVP_DigestInit_ex(ctx, EVP_md5(), NULL)) {
msyslog(LOG_ERR,
"MD5 init failed");