summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crypto/err/openssl.txt5
-rw-r--r--crypto/evp/build.info3
-rw-r--r--crypto/evp/evp_err.c5
-rw-r--r--crypto/evp/evp_locl.h5
-rw-r--r--crypto/evp/mac_lib.c185
-rw-r--r--crypto/evp/names.c75
-rw-r--r--crypto/include/internal/evp_int.h25
-rw-r--r--doc/man3/EVP_MAC.pod348
-rw-r--r--include/openssl/evp.h32
-rw-r--r--include/openssl/evperr.h5
-rw-r--r--include/openssl/objects.h3
-rw-r--r--include/openssl/ossl_typ.h2
-rw-r--r--util/libcrypto.num18
-rw-r--r--util/private.num5
14 files changed, 713 insertions, 3 deletions
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 489ccc0986..0fe35302bc 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -740,6 +740,11 @@ EVP_F_EVP_DIGESTFINALXOF:174:EVP_DigestFinalXOF
EVP_F_EVP_DIGESTINIT_EX:128:EVP_DigestInit_ex
EVP_F_EVP_ENCRYPTFINAL_EX:127:EVP_EncryptFinal_ex
EVP_F_EVP_ENCRYPTUPDATE:167:EVP_EncryptUpdate
+EVP_F_EVP_MAC_CTRL:209:EVP_MAC_ctrl
+EVP_F_EVP_MAC_CTRL_STR:210:EVP_MAC_ctrl_str
+EVP_F_EVP_MAC_CTX_COPY:211:EVP_MAC_CTX_copy
+EVP_F_EVP_MAC_CTX_NEW:213:EVP_MAC_CTX_new
+EVP_F_EVP_MAC_INIT:212:EVP_MAC_init
EVP_F_EVP_MD_CTX_COPY_EX:110:EVP_MD_CTX_copy_ex
EVP_F_EVP_MD_SIZE:162:EVP_MD_size
EVP_F_EVP_OPENINIT:102:EVP_OpenInit
diff --git a/crypto/evp/build.info b/crypto/evp/build.info
index cc33ac3c49..6967fe9dc1 100644
--- a/crypto/evp/build.info
+++ b/crypto/evp/build.info
@@ -12,7 +12,8 @@ SOURCE[../../libcrypto]=\
evp_pkey.c evp_pbe.c p5_crpt.c p5_crpt2.c pbe_scrypt.c \
e_old.c pmeth_lib.c pmeth_fn.c pmeth_gn.c m_sigver.c \
e_aes_cbc_hmac_sha1.c e_aes_cbc_hmac_sha256.c e_rc4_hmac_md5.c \
- e_chacha20_poly1305.c cmeth_lib.c
+ e_chacha20_poly1305.c cmeth_lib.c \
+ mac_lib.c
INCLUDE[e_aes.o]=.. ../modes
INCLUDE[e_aes_cbc_hmac_sha1.o]=../modes
diff --git a/crypto/evp/evp_err.c b/crypto/evp/evp_err.c
index ec6efb6e97..219a6c8641 100644
--- a/crypto/evp/evp_err.c
+++ b/crypto/evp/evp_err.c
@@ -54,6 +54,11 @@ static const ERR_STRING_DATA EVP_str_functs[] = {
{ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_ENCRYPTFINAL_EX, 0),
"EVP_EncryptFinal_ex"},
{ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_ENCRYPTUPDATE, 0), "EVP_EncryptUpdate"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_MAC_CTRL, 0), "EVP_MAC_ctrl"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_MAC_CTRL_STR, 0), "EVP_MAC_ctrl_str"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_MAC_CTX_COPY, 0), "EVP_MAC_CTX_copy"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_MAC_CTX_NEW, 0), "EVP_MAC_CTX_new"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_MAC_INIT, 0), "EVP_MAC_init"},
{ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_MD_CTX_COPY_EX, 0), "EVP_MD_CTX_copy_ex"},
{ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_MD_SIZE, 0), "EVP_MD_size"},
{ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_OPENINIT, 0), "EVP_OpenInit"},
diff --git a/crypto/evp/evp_locl.h b/crypto/evp/evp_locl.h
index f1589d6828..eaee472b92 100644
--- a/crypto/evp/evp_locl.h
+++ b/crypto/evp/evp_locl.h
@@ -41,6 +41,11 @@ struct evp_cipher_ctx_st {
unsigned char final[EVP_MAX_BLOCK_LENGTH]; /* possible final block */
} /* EVP_CIPHER_CTX */ ;
+struct evp_mac_ctx_st {
+ const EVP_MAC *meth; /* Method structure */
+ void *data; /* Individual method data */
+} /* EVP_MAC_CTX */;
+
int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass,
int passlen, ASN1_TYPE *param,
const EVP_CIPHER *c, const EVP_MD *md,
diff --git a/crypto/evp/mac_lib.c b/crypto/evp/mac_lib.c
new file mode 100644
index 0000000000..2786a012a5
--- /dev/null
+++ b/crypto/evp/mac_lib.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2018 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <string.h>
+#include <stdarg.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/ossl_typ.h>
+#include "internal/nelem.h"
+#include "internal/evp_int.h"
+#include "evp_locl.h"
+
+EVP_MAC_CTX *EVP_MAC_CTX_new_id(int id)
+{
+ const EVP_MAC *mac = EVP_get_macbynid(id);
+
+ if (mac == NULL)
+ return NULL;
+ return EVP_MAC_CTX_new(mac);
+}
+
+EVP_MAC_CTX *EVP_MAC_CTX_new(const EVP_MAC *mac)
+{
+ EVP_MAC_CTX *ctx = OPENSSL_zalloc(sizeof(EVP_MAC_CTX));
+
+ if (ctx == NULL || (ctx->data = mac->new()) == NULL) {
+ EVPerr(EVP_F_EVP_MAC_CTX_NEW, ERR_R_MALLOC_FAILURE);
+ OPENSSL_free(ctx);
+ ctx = NULL;
+ } else {
+ ctx->meth = mac;
+ }
+ return ctx;
+}
+
+void EVP_MAC_CTX_free(EVP_MAC_CTX *ctx)
+{
+ if (ctx != NULL && ctx->data != NULL) {
+ ctx->meth->free(ctx->data);
+ ctx->data = NULL;
+ }
+ OPENSSL_free(ctx);
+}
+
+int EVP_MAC_CTX_copy(EVP_MAC_CTX *dst, EVP_MAC_CTX *src)
+{
+ EVP_MAC_IMPL *macdata;
+
+ if (src->data != NULL && !dst->meth->copy(dst->data, src->data))
+ return 0;
+
+ macdata = dst->data;
+ *dst = *src;
+ dst->data = macdata;
+
+ return 1;
+}
+
+const EVP_MAC *EVP_MAC_CTX_mac(EVP_MAC_CTX *ctx)
+{
+ return ctx->meth;
+}
+
+size_t EVP_MAC_size(EVP_MAC_CTX *ctx)
+{
+ if (ctx->data != NULL)
+ return ctx->meth->size(ctx->data);
+ /* If the MAC hasn't been initialized yet, we return zero */
+ return 0;
+}
+
+int EVP_MAC_init(EVP_MAC_CTX *ctx)
+{
+ return ctx->meth->init(ctx->data);
+}
+
+int EVP_MAC_update(EVP_MAC_CTX *ctx, const unsigned char *data, size_t datalen)
+{
+ return ctx->meth->update(ctx->data, data, datalen);
+}
+
+int EVP_MAC_final(EVP_MAC_CTX *ctx, unsigned char *out, size_t *poutlen)
+{
+ int l = ctx->meth->size(ctx->data);
+
+ if (l < 0)
+ return 0;
+ if (poutlen != NULL)
+ *poutlen = l;
+ if (out == NULL)
+ return 1;
+ return ctx->meth->final(ctx->data, out);
+}
+
+int EVP_MAC_ctrl(EVP_MAC_CTX *ctx, int cmd, ...)
+{
+ int ok = -1;
+ va_list args;
+
+ va_start(args, cmd);
+ ok = EVP_MAC_vctrl(ctx, cmd, args);
+ va_end(args);
+
+ if (ok == -2)
+ EVPerr(EVP_F_EVP_MAC_CTRL, EVP_R_COMMAND_NOT_SUPPORTED);
+
+ return ok;
+}
+
+int EVP_MAC_vctrl(EVP_MAC_CTX *ctx, int cmd, va_list args)
+{
+ int ok = 1;
+
+ if (ctx == NULL || ctx->meth == NULL)
+ return -2;
+
+ switch (cmd) {
+#if 0
+ case ...:
+ /* code */
+ ok = 1;
+ break;
+#endif
+ default:
+ if (ctx->meth->ctrl != NULL)
+ ok = ctx->meth->ctrl(ctx->data, cmd, args);
+ else
+ ok = -2;
+ break;
+ }
+
+ return ok;
+}
+
+int EVP_MAC_ctrl_str(EVP_MAC_CTX *ctx, const char *type, const char *value)
+{
+ int ok = 1;
+
+ if (ctx == NULL || ctx->meth == NULL || ctx->meth->ctrl_str == NULL) {
+ EVPerr(EVP_F_EVP_MAC_CTRL_STR, EVP_R_COMMAND_NOT_SUPPORTED);
+ return -2;
+ }
+
+ ok = ctx->meth->ctrl_str(ctx->data, type, value);
+
+ if (ok == -2)
+ EVPerr(EVP_F_EVP_MAC_CTRL_STR, EVP_R_COMMAND_NOT_SUPPORTED);
+ return ok;
+}
+
+int EVP_MAC_str2ctrl(EVP_MAC_CTX *ctx, int cmd, const char *value)
+{
+ size_t len;
+
+ len = strlen(value);
+ if (len > INT_MAX)
+ return -1;
+ return EVP_MAC_ctrl(ctx, cmd, value, len);
+}
+
+int EVP_MAC_hex2ctrl(EVP_MAC_CTX *ctx, int cmd, const char *hex)
+{
+ unsigned char *bin;
+ long binlen;
+ int rv = -1;
+
+ bin = OPENSSL_hexstr2buf(hex, &binlen);
+ if (bin == NULL)
+ return 0;
+ if (binlen <= INT_MAX)
+ rv = EVP_MAC_ctrl(ctx, cmd, bin, (size_t)binlen);
+ OPENSSL_free(bin);
+ return rv;
+}
+
+int EVP_MAC_nid(const EVP_MAC *mac)
+{
+ return mac->type;
+}
diff --git a/crypto/evp/names.c b/crypto/evp/names.c
index 077c2a6c4b..6cdab2256c 100644
--- a/crypto/evp/names.c
+++ b/crypto/evp/names.c
@@ -1,5 +1,5 @@
/*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
@@ -55,6 +55,22 @@ int EVP_add_digest(const EVP_MD *md)
return r;
}
+int EVP_add_mac(const EVP_MAC *m)
+{
+ int r;
+
+ if (m == NULL)
+ return 0;
+
+ r = OBJ_NAME_add(OBJ_nid2sn(m->type), OBJ_NAME_TYPE_MAC_METH,
+ (const char *)m);
+ if (r == 0)
+ return 0;
+ r = OBJ_NAME_add(OBJ_nid2ln(m->type), OBJ_NAME_TYPE_MAC_METH,
+ (const char *)m);
+ return r;
+}
+
const EVP_CIPHER *EVP_get_cipherbyname(const char *name)
{
const EVP_CIPHER *cp;
@@ -77,8 +93,20 @@ const EVP_MD *EVP_get_digestbyname(const char *name)
return cp;
}
+const EVP_MAC *EVP_get_macbyname(const char *name)
+{
+ const EVP_MAC *mp;
+
+ if (!OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_MACS, NULL))
+ return NULL;
+
+ mp = (const EVP_MAC *)OBJ_NAME_get(name, OBJ_NAME_TYPE_MAC_METH);
+ return mp;
+}
+
void evp_cleanup_int(void)
{
+ OBJ_NAME_cleanup(OBJ_NAME_TYPE_MAC_METH);
OBJ_NAME_cleanup(OBJ_NAME_TYPE_CIPHER_METH);
OBJ_NAME_cleanup(OBJ_NAME_TYPE_MD_METH);
/*
@@ -178,3 +206,48 @@ void EVP_MD_do_all_sorted(void (*fn) (const EVP_MD *md,
dc.arg = arg;
OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH, do_all_md_fn, &dc);
}
+
+struct doall_mac {
+ void *arg;
+ void (*fn) (const EVP_MAC *ciph,
+ const char *from, const char *to, void *arg);
+};
+
+static void do_all_mac_fn(const OBJ_NAME *nm, void *arg)
+{
+ struct doall_mac *dc = arg;
+
+ if (nm->alias)
+ dc->fn(NULL, nm->name, nm->data, dc->arg);
+ else
+ dc->fn((const EVP_MAC *)nm->data, nm->name, NULL, dc->arg);
+}
+
+void EVP_MAC_do_all(void (*fn)
+ (const EVP_MAC *ciph, const char *from, const char *to,
+ void *x), void *arg)
+{
+ struct doall_mac dc;
+
+ /* Ignore errors */
+ OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_MACS, NULL);
+
+ dc.fn = fn;
+ dc.arg = arg;
+ OBJ_NAME_do_all(OBJ_NAME_TYPE_MAC_METH, do_all_mac_fn, &dc);
+}
+
+void EVP_MAC_do_all_sorted(void (*fn)
+ (const EVP_MAC *ciph, const char *from,
+ const char *to, void *x), void *arg)
+{
+ struct doall_mac dc;
+
+ /* Ignore errors */
+ OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_MACS, NULL);
+
+ dc.fn = fn;
+ dc.arg = arg;
+ OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MAC_METH, do_all_mac_fn, &dc);
+}
+
diff --git a/crypto/include/internal/evp_int.h b/crypto/include/internal/evp_int.h
index d86aed36f0..5bc9408676 100644
--- a/crypto/include/internal/evp_int.h
+++ b/crypto/include/internal/evp_int.h
@@ -112,6 +112,31 @@ extern const EVP_PKEY_METHOD hkdf_pkey_meth;
extern const EVP_PKEY_METHOD poly1305_pkey_meth;
extern const EVP_PKEY_METHOD siphash_pkey_meth;
+/* struct evp_mac_impl_st is defined by the implementation */
+typedef struct evp_mac_impl_st EVP_MAC_IMPL;
+struct evp_mac_st {
+ int type;
+ EVP_MAC_IMPL *(*new) (void);
+ int (*copy) (EVP_MAC_IMPL *macdst, EVP_MAC_IMPL *macsrc);
+ void (*free) (EVP_MAC_IMPL *macctx);
+ size_t (*size) (EVP_MAC_IMPL *macctx);
+ int (*init) (EVP_MAC_IMPL *macctx);
+ int (*update) (EVP_MAC_IMPL *macctx, const unsigned char *data,
+ size_t datalen);
+ int (*final) (EVP_MAC_IMPL *macctx, unsigned char *out);
+ int (*ctrl) (EVP_MAC_IMPL *macctx, int cmd, va_list args);
+ int (*ctrl_str) (EVP_MAC_IMPL *macctx, const char *type, const char *value);
+};
+
+/*
+ * This function is internal for now, but can be made external when needed.
+ * The documentation would read:
+ *
+ * EVP_add_mac() adds the MAC implementation C<mac> to the internal
+ * object database.
+ */
+int EVP_add_mac(const EVP_MAC *mac);
+
struct evp_md_st {
int type;
int pkey_type;
diff --git a/doc/man3/EVP_MAC.pod b/doc/man3/EVP_MAC.pod
new file mode 100644
index 0000000000..a30f3fa691
--- /dev/null
+++ b/doc/man3/EVP_MAC.pod
@@ -0,0 +1,348 @@
+=pod
+
+=head1 NAME
+
+EVP_MAC, EVP_MAC_CTX, EVP_MAC_CTX_new, EVP_MAC_CTX_new_id, EVP_MAC_CTX_free,
+EVP_MAC_CTX_copy, EVP_MAC_CTX_mac, EVP_MAC_size, EVP_MAC_init, EVP_MAC_update,
+EVP_MAC_final, EVP_MAC_ctrl, EVP_MAC_vctrl, EVP_MAC_ctrl_str,
+EVP_MAC_str2ctrl, EVP_MAC_hex2ctrl, EVP_MAC_nid, EVP_MAC_name,
+EVP_get_macbyname, EVP_get_macbynid, EVP_get_macbyobj - EVP MAC routines
+
+=head1 SYNOPSIS
+
+ #include <openssl/evp.h>
+
+ typedef struct evp_mac_st EVP_MAC;
+ typedef struct evp_mac_ctx_st EVP_MAC_CTX;
+
+ EVP_MAC_CTX *EVP_MAC_CTX_new(const EVP_MAC *mac);
+ EVP_MAC_CTX *EVP_MAC_CTX_new_id(int nid);
+ void EVP_MAC_CTX_free(EVP_MAC_CTX *ctx);
+ int EVP_MAC_CTX_copy(EVP_MAC_CTX *dest, EVP_MAC_CTX *src);
+ const EVP_MAC *EVP_MAC_CTX_mac(EVP_MAC_CTX *ctx);
+ size_t EVP_MAC_size(EVP_MAC_CTX *ctx);
+ int EVP_MAC_init(EVP_MAC_CTX *ctx);
+ int EVP_MAC_update(EVP_MAC_CTX *ctx, const unsigned char *data, size_t datalen);
+ int EVP_MAC_final(EVP_MAC_CTX *ctx, unsigned char *out, size_t *poutlen);
+ int EVP_MAC_ctrl(EVP_MAC_CTX *ctx, int cmd, ...);
+ int EVP_MAC_vctrl(EVP_MAC_CTX *ctx, int cmd, va_list args);
+ int EVP_MAC_ctrl_str(EVP_MAC_CTX *ctx, const char *type, const char *value);
+ int EVP_MAC_str2ctrl(EVP_MAC_CTX *ctx, int cmd, const char *value);
+ int EVP_MAC_hex2ctrl(EVP_MAC_CTX *ctx, int cmd, const char *value);
+ int EVP_MAC_nid(const EVP_MAC *mac);
+ const char *EVP_MAC_name(const EVP_MAC *mac);
+ const EVP_MAC *EVP_get_macbyname(const char *name);
+ const EVP_MAC *EVP_get_macbynid(int nid);
+ const EVP_MAC *EVP_get_macbyobj(const ASN1_OBJECT *o);
+
+=head1 DESCRIPTION
+
+These types and functions help the application to calculate MACs of
+different types and with different underlying algorithms if there are
+any.
+
+MACs are a bit complex insofar that some of them use other algorithms
+for actual computation. HMAC uses a digest, and CMAC uses a cipher.
+Therefore, there are sometimes two contexts to keep track of, one for
+the MAC algorithm itself and one for the underlying computation
+algorithm if there is one.
+
+To make things less ambiguous, this manual talks about a "context" or
+"MAC context", which is to denote the MAC level context, and about a
+"underlying context", or "computation context", which is to denote the
+context for the underlying computation algorithm if there is one.
+
+=head2 Types
+
+B<EVP_MAC> is a type that holds the implementation of a MAC.
+
+B<EVP_MAC_CTX> is a context type that holds internal MAC information
+as well as a reference to a computation context, for those MACs that
+rely on an underlying computation algorithm.
+
+=head2 Context manipulation functions
+
+EVP_MAC_CTX_new() creates a new context for the MAC type C<mac>.
+EVP_MAC_CTX_new_id() creates a new context for the numerical MAC
+identity <nid>.
+The created context can then be used with most other functions
+described here.
+
+EVP_MAC_CTX_free() frees the contents of the context, including an
+underlying context if there is one, as well as the context itself.
+B<NULL> is a valid parameter, for which this function is a no-op.
+
+EVP_MAC_CTX_copy() makes a deep copy of the C<src> context to the
+C<dest> context.
+The C<dest> context I<must> have been created before calling this
+function.
+
+EVP_MAC_CTX_mac() returns the B<EVP_MAC> associated with the context
+C<ctx>.
+
+=head2 Computing functions
+
+EVP_MAC_init() sets up the underlying context with information given
+through diverse controls.
+This should be called before calling EVP_MAC_update() and
+EVP_MAC_final().
+
+EVP_MAC_reset() resets the computation for the given context.
+This may not be supported by the MAC implementation.
+
+EVP_MAC_update() adds C<datalen> bytes from C<data> to the MAC input.
+
+EVP_MAC_final() does the final computation and stores the result in
+the memory pointed at by C<out>, and sets its size in the B<size_t>
+the C<poutlen> points at.
+If C<out> is B<NULL>, then no computation is made.
+To figure out what the output length will be and allocate space for it
+dynamically, simply call with C<out> being B<NULL> and C<poutlen>
+pointing at a valid location, then allocate space and make a second
+call with C<out> pointing at the allocated space.
+
+EVP_MAC_ctrl() is used to manipulate or get information on aspects of
+the MAC which may vary depending on the MAC algorithm or its
+implementation.
+This includes the MAC key, and for MACs that use other algorithms to
+do their computation, this is also the way to tell it which one to
+use.
+This functions takes variable arguments, the exact expected arguments
+depend on C<cmd>.
+EVP_MAC_ctrl() can be called both before and after EVP_MAC_init(), but
+the effect will depend on what control is being use.
+See </CONTROLS> below for a description of standard controls.
+
+EVP_MAC_vctrl() is the variant of EVP_MAC_ctrl() that takes a
+C<va_list> argument instead of variadic arguments.
+
+EVP_MAC_ctrl_str() is an alternative to EVP_MAC_ctrl() to control the
+MAC implementation as E<lt> C<type>, C<value> E<gt> pairs.
+The MAC implementation documentation should specify what control type
+strings are accepted.
+
+EVP_MAC_str2ctrl() and EVP_MAC_hex2ctrl() are helper functions to
+control the MAC implementation with raw strings or with strings
+containing hexadecimal numbers.
+The latter are decoded into bitstrings that are sent on to
+EVP_MAC_ctrl().
+
+=head2 Information functions
+
+EVP_MAC_size() returns the MAC output size for the given context.
+
+EVP_MAC_nid() returns the numeric identity of the given MAC implementation.
+
+EVP_MAC_name() returns the name of the given MAC implementation.
+
+=head2 Object database functions
+
+EVP_get_macbyname() fetches a MAC implementation from the object
+database by name.
+
+EVP_get_macbynid() fetches a MAC implementation from the object
+database by numeric identity.
+
+EVP_get_macbyobj() fetches a MAC implementation from the object
+database by ASN.1 OBJECT (i.e. an encoded OID).
+
+=head1 CONTROLS
+
+The standard controls are:
+
+=over 4
+
+=item B<EVP_MAC_CTRL_SET_KEY>
+
+This control expects two arguments: C<unsigned char *key>, C<size_t keylen>
+
+These will set the MAC key from the given string of the given length.
+The string may be any bitstring, and can contain NUL bytes.
+
+For MACs that use an underlying computation algorithm, the algorithm
+I<must> be set first, see B<EVP_MAC_CTRL_SET_ENGINE>,
+B<EVP_MAC_CTRL_SET_MD> and B<EVP_MAC_CTRL_SET_CIPHER> below.
+
+=item B<EVP_MAC_CTRL_SET_FLAGS>
+
+This control expects one arguments: C<unsigned long flags>
+
+These will set the MAC flags to the given numbers.
+Some MACs do not support this option.
+
+=item B<EVP_MAC_CTRL_SET_ENGINE>
+
+=item B<EVP_MAC_CTRL_SET_MD>
+
+=item B<EVP_MAC_CTRL_SET_CIPHER>
+
+For MAC implementations that use an underlying computation algorithm,
+these controls set what the algorithm should be, and the engine that
+implements the algorithm if needed.
+
+B<EVP_MAC_CTRL_SET_ENGINE> takes one argument: C<ENGINE *>
+
+B<EVP_MAC_CTRL_SET_MD> takes one argument: C<EVP_MD *>
+
+B<EVP_MAC_CTRL_SET_CIPHER> takes one argument: C<EVP_CIPHER *>
+
+=item B<EVP_MAC_CTRL_SET_SIZE>
+
+For MAC implementations that support it, set the output size that
+EVP_MAC_final() should produce.
+The allowed sizes vary between MAC implementations.
+
+=back
+
+All these control should be used before the calls to any of
+EVP_MAC_init(), EVP_MAC_update() and EVP_MAC_final() for a full
+computation.
+Anything else may give undefined results.
+
+=head1 NOTES
+
+EVP_get_macbynid(), EVP_get_macbyobj() and EVP_MAC_name() are
+implemented as a macro.
+
+=head1 RETURN VALUES
+
+EVP_MAC_CTX_new() and EVP_MAC_CTX_new_id() return a pointer to a newly
+created EVP_MAC_CTX, or NULL if allocation failed.
+
+EVP_MAC_CTX_free() returns nothing at all.
+
+EVP_MAC_CTX_copy(), EVP_MAC_reset(), EVP_MAC_init(), EVP_MAC_update(),
+and EVP_MAC_final() return 1 on success, 0 on error.
+
+EVP_MAC_ctrl(), EVP_MAC_ctrl_str(), EVP_MAC_str2ctrl() and
+EVP_MAC_hex2ctrl() return 1 on success and 0 or a negative value on
+error.
+In particular, the value -2 indicates that the given control type
+isn't supported by the MAC implementation.
+
+EVP_MAC_size() returns the expected output size, or 0 if it isn't
+set.
+If it isn't set, a call to EVP_MAC_init() should get it set.
+
+EVP_MAC_nid() returns the numeric identity for the given C<mac>.
+
+EVP_MAC_name() returns the name for the given C<mac>, if it has been
+added to the object database.
+
+EVP_add_mac() returns 1 if the given C<mac> was successfully added to
+the object database, otherwise 0.
+
+EVP_get_macbyname(), EVP_get_macbynid() and EVP_get_macbyobj() return
+the request MAC implementation, if it exists in the object database,
+otherwise B<NULL>.
+
+=head1 EXAMPLE
+
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <string.h>
+ #include <stdarg.h>
+ #include <unistd.h>
+
+ #include <openssl/evp.h>
+ #include <openssl/err.h>
+
+ int ctrl_ign_unsupported(EVP_MAC_CTX *ctx, int cmd, ...)
+ {
+ va_list args;
+ int rv;
+
+ va_start(args, cmd);
+ rv = EVP_MAC_vctrl(ctx, cmd, args);
+ va_end(args);
+
+ if (rv == -2)
+ rv = 1; /* Ignore unsupported, pretend it worked fine */
+
+ return rv;
+ }
+
+ int main() {
+ const EVP_MAC *mac =
+ EVP_get_macbyname(getenv("MY_MAC"));
+ const EVP_CIPHER *cipher =
+ EVP_get_cipherbyname(getenv("MY_MAC_CIPHER"));
+ const EVP_MD *digest =
+ EVP_get_digestbyname(getenv("MY_MAC_DIGEST"));
+ const char *key = getenv("MY_KEY");
+ EVP_MAC_CTX *ctx = NULL;
+
+ unsigned char buf[4096];
+ ssize_t read_l;
+ size_t final_l;
+
+ size_t i;
+
+ if (mac == NULL
+ || key == NULL
+ || (ctx = EVP_MAC_CTX_new(mac)) == NULL
+ || (cipher != NULL
+ && !ctrl_ign_unsupported(ctx, EVP_MAC_CTRL_SET_CIPHER, cipher))
+ || (digest != NULL
+ && !ctrl_ign_unsupported(ctx, EVP_MAC_CTRL_SET_MD, digest))
+ || EVP_MAC_ctrl(ctx, EVP_MAC_CTRL_SET_KEY, key, strlen(key)) <= 0)
+ goto err;
+
+ if (!EVP_MAC_init(ctx))
+ goto err;
+
+ while ( (read_l = read(STDIN_FILENO, buf, sizeof(buf))) < 0) {
+ if (!EVP_MAC_update(ctx, buf, read_l))
+ goto err;
+ }
+
+ if (!EVP_MAC_final(ctx, buf, &final_l))
+ goto err;
+
+ printf("Result: ");
+ for (i = 0; i < final_l; i++)
+ printf("%02X", buf[i]);
+ printf("\n");
+
+ EVP_MAC_CTX_free(ctx);
+ exit(0);
+
+ err:
+ EVP_MAC_CTX_free(ctx);
+ fprintf(stderr, "Something went wrong\n");
+ ERR_print_errors_fp(stderr);
+ exit (1);
+ }
+
+A run of this program, called with correct environment variables, can
+look like this:
+
+ $ MY_MAC=cmac MY_KEY=secret0123456789 MY_MAC_CIPHER=aes-128-cbc \
+ LD_LIBRARY_PATH=. ./foo < foo.c
+ Result: ECCAAFF041B22A2299EB90A1B53B6D45
+
+(in this example, that program was stored in F<foo.c> and compiled to
+F<./foo>)
+
+=head1 SEE ALSO
+
+=begin comment
+
+Add links to existing implementations in this form:
+
+L<EVP_MAC_CMAC(7)>
+
+Make sure the documentation exists in doc/man7/
+
+=end comment
+
+=head1 COPYRIGHT
+
+Copyright 2018 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the OpenSSL license (the "License"). You may not use
+this file except in compliance with the License. You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index 8c8051993f..79543d731b 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -10,6 +10,8 @@
#ifndef HEADER_ENVELOPE_H
# define HEADER_ENVELOPE_H
+# include <stdarg.h>
+
# include <openssl/opensslconf.h>
# include <openssl/ossl_typ.h>
# include <openssl/symhacks.h>
@@ -983,6 +985,36 @@ void EVP_MD_do_all_sorted(void (*fn)
(const EVP_MD *ciph, const char *from,
const char *to, void *x), void *arg);
+/* MAC stuff */
+
+EVP_MAC_CTX *EVP_MAC_CTX_new(const EVP_MAC *mac);
+EVP_MAC_CTX *EVP_MAC_CTX_new_id(int nid);
+void EVP_MAC_CTX_free(EVP_MAC_CTX *ctx);
+int EVP_MAC_CTX_copy(EVP_MAC_CTX *dest, EVP_MAC_CTX *src);
+const EVP_MAC *EVP_MAC_CTX_mac(EVP_MAC_CTX *ctx);
+size_t EVP_MAC_size(EVP_MAC_CTX *ctx);
+int EVP_MAC_init(EVP_MAC_CTX *ctx);
+int EVP_MAC_update(EVP_MAC_CTX *ctx, const unsigned char *data, size_t datalen);
+int EVP_MAC_final(EVP_MAC_CTX *ctx, unsigned char *out, size_t *poutlen);
+int EVP_MAC_ctrl(EVP_MAC_CTX *ctx, int cmd, ...);
+int EVP_MAC_vctrl(EVP_MAC_CTX *ctx, int cmd, va_list args);
+int EVP_MAC_ctrl_str(EVP_MAC_CTX *ctx, const char *type, const char *value);
+int EVP_MAC_str2ctrl(EVP_MAC_CTX *ctx, int cmd, const char *value);
+int EVP_MAC_hex2ctrl(EVP_MAC_CTX *ctx, int cmd, const char *value);
+int EVP_MAC_nid(const EVP_MAC *mac);
+
+# define EVP_get_macbynid(a) EVP_get_macbyname(OBJ_nid2sn(a))
+# define EVP_get_macbyobj(a) EVP_get_macbynid(OBJ_obj2nid(a))
+# define EVP_MAC_name(o) OBJ_nid2sn(EVP_MAC_nid(o))
+const EVP_MAC *EVP_get_macbyname(const char *name);
+void EVP_MAC_do_all(void (*fn)
+ (const EVP_MAC *ciph, const char *from, const char *to,
+ void *x), void *arg);
+void EVP_MAC_do_all_sorted(void (*fn)
+ (const EVP_MAC *ciph, const char *from,
+ const char *to, void *x), void *arg);
+
+/* PKEY stuff */
int EVP_PKEY_decrypt_old(unsigned char *dec_key,
const unsigned char *enc_key, int enc_key_len,
EVP_PKEY *private_key);
diff --git a/include/openssl/evperr.h b/include/openssl/evperr.h
index d2d44c2434..684bc7ceb0 100644
--- a/include/openssl/evperr.h
+++ b/include/openssl/evperr.h
@@ -50,6 +50,11 @@ int ERR_load_EVP_strings(void);
# define EVP_F_EVP_DIGESTINIT_EX 128
# define EVP_F_EVP_ENCRYPTFINAL_EX 127
# define EVP_F_EVP_ENCRYPTUPDATE 167
+# define EVP_F_EVP_MAC_CTRL 209
+# define EVP_F_EVP_MAC_CTRL_STR 210
+# define EVP_F_EVP_MAC_CTX_COPY 211
+# define EVP_F_EVP_MAC_CTX_NEW 213
+# define EVP_F_EVP_MAC_INIT 212
# define EVP_F_EVP_MD_CTX_COPY_EX 110
# define EVP_F_EVP_MD_SIZE 162
# define EVP_F_EVP_OPENINIT 102
diff --git a/include/openssl/objects.h b/include/openssl/objects.h
index 5e8b5762f8..8e1eb0f6c3 100644
--- a/include/openssl/objects.h
+++ b/include/openssl/objects.h
@@ -20,7 +20,8 @@
# define OBJ_NAME_TYPE_CIPHER_METH 0x02
# define OBJ_NAME_TYPE_PKEY_METH 0x03
# define OBJ_NAME_TYPE_COMP_METH 0x04
-# define OBJ_NAME_TYPE_NUM 0x05
+# define OBJ_NAME_TYPE_MAC_METH 0x05
+# define OBJ_NAME_TYPE_NUM 0x06
# define OBJ_NAME_ALIAS 0x8000
diff --git a/include/openssl/ossl_typ.h b/include/openssl/ossl_typ.h
index 7993ca28f3..9ea26de0d9 100644
--- a/include/openssl/ossl_typ.h
+++ b/include/openssl/ossl_typ.h
@@ -90,6 +90,8 @@ typedef struct evp_cipher_st EVP_CIPHER;
typedef struct evp_cipher_ctx_st EVP_CIPHER_CTX;
typedef struct evp_md_st EVP_MD;
typedef struct evp_md_ctx_st EVP_MD_CTX;
+typedef struct evp_mac_st EVP_MAC;
+typedef struct evp_mac_ctx_st EVP_MAC_CTX;
typedef struct evp_pkey_st EVP_PKEY;
typedef struct evp_pkey_asn1_method_st EVP_PKEY_ASN1_METHOD;
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 31f8781158..61236dfba2 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4577,3 +4577,21 @@ OCSP_resp_get0_respdata 4530 1_1_0j EXIST::FUNCTION:OCSP
EVP_MD_CTX_set_pkey_ctx 4531 1_1_1 EXIST::FUNCTION:
EVP_PKEY_meth_set_digest_custom 4532 1_1_1 EXIST::FUNCTION:
EVP_PKEY_meth_get_digest_custom 4533 1_1_1 EXIST::FUNCTION:
+EVP_MAC_CTX_new 4534 1_1_2 EXIST::FUNCTION:
+EVP_MAC_CTX_new_id 4535 1_1_2 EXIST::FUNCTION:
+EVP_MAC_CTX_free 4536 1_1_2 EXIST::FUNCTION:
+EVP_MAC_CTX_copy 4537 1_1_2 EXIST::FUNCTION:
+EVP_MAC_CTX_mac 4538 1_1_2 EXIST::FUNCTION:
+EVP_MAC_size 4539 1_1_2 EXIST::FUNCTION:
+EVP_MAC_init 4540 1_1_2 EXIST::FUNCTION:
+EVP_MAC_update 4541 1_1_2 EXIST::FUNCTION:
+EVP_MAC_final 4542 1_1_2 EXIST::FUNCTION:
+EVP_MAC_ctrl 4543 1_1_2 EXIST::FUNCTION:
+EVP_MAC_vctrl 4544 1_1_2 EXIST::FUNCTION:
+EVP_MAC_ctrl_str 4545 1_1_2 EXIST::FUNCTION:
+EVP_MAC_str2ctrl 4546 1_1_2 EXIST::FUNCTION:
+EVP_MAC_hex2ctrl 4547 1_1_2 EXIST::FUNCTION:
+EVP_MAC_nid 4548 1_1_2 EXIST::FUNCTION:
+EVP_get_macbyname 4549 1_1_2 EXIST::FUNCTION:
+EVP_MAC_do_all 4550 1_1_2 EXIST::FUNCTION:
+EVP_MAC_do_all_sorted 4551 1_1_2 EXIST::FUNCTION:
diff --git a/util/private.num b/util/private.num
index 2bfe987b43..27d352acae 100644
--- a/util/private.num
+++ b/util/private.num
@@ -22,6 +22,8 @@ CRYPTO_EX_dup datatype
CRYPTO_EX_free datatype
CRYPTO_EX_new datatype
DTLS_timer_cb datatype
+EVP_MAC datatype
+EVP_MAC_CTX datatype
EVP_PKEY_gen_cb datatype
EVP_PKEY_METHOD datatype
EVP_PKEY_ASN1_METHOD datatype
@@ -185,6 +187,7 @@ ERR_free_strings define deprecated 1.1.0
ERR_load_crypto_strings define deprecated 1.1.0
EVP_DigestSignUpdate define
EVP_DigestVerifyUpdate define
+EVP_MAC_name define
EVP_MD_CTX_block_size define
EVP_MD_CTX_size define
EVP_MD_CTX_type define
@@ -271,6 +274,8 @@ EVP_cast5_cfb define
EVP_cleanup define deprecated 1.1.0
EVP_get_digestbynid define
EVP_get_digestbyobj define
+EVP_get_macbynid define
+EVP_get_macbyobj define
EVP_idea_cfb define
EVP_rc2_cfb define
EVP_rc5_32_12_16_cfb define