Add EVP_MAC API
authorRichard Levitte <levitte@openssl.org>
Fri, 12 Oct 2018 20:27:18 +0000 (22:27 +0200)
committerRichard Levitte <levitte@openssl.org>
Mon, 29 Oct 2018 12:35:19 +0000 (13:35 +0100)
We currently implement EVP MAC methods as EVP_PKEY methods.  This
change creates a separate EVP API for MACs, to replace the current
EVP_PKEY ones.

A note about this EVP API and how it interfaces with underlying MAC
implementations:

Other EVP APIs pass the EVP API context down to implementations, and
it can be observed that the implementations use the pointer to their
own private data almost exclusively.  The EVP_MAC API deviates from
that pattern by passing the pointer to the implementation's private
data directly, and thereby deny the implementations access to the
EVP_MAC context structure.  This change is made to provide a clearer
separation between the EVP library itself and the implementations of
its supported algorithm classes.

Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/7393)

14 files changed:
crypto/err/openssl.txt
crypto/evp/build.info
crypto/evp/evp_err.c
crypto/evp/evp_locl.h
crypto/evp/mac_lib.c [new file with mode: 0644]
crypto/evp/names.c
crypto/include/internal/evp_int.h
doc/man3/EVP_MAC.pod [new file with mode: 0644]
include/openssl/evp.h
include/openssl/evperr.h
include/openssl/objects.h
include/openssl/ossl_typ.h
util/libcrypto.num
util/private.num

index 489ccc0..0fe3530 100644 (file)
@@ -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
index cc33ac3..6967fe9 100644 (file)
@@ -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
index ec6efb6..219a6c8 100644 (file)
@@ -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"},
index f1589d6..eaee472 100644 (file)
@@ -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 (file)
index 0000000..2786a01
--- /dev/null
@@ -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;
+}
index 077c2a6..6cdab22 100644 (file)
@@ -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);
+}
+
index d86aed3..5bc9408 100644 (file)
@@ -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 (file)
index 0000000..a30f3fa
--- /dev/null
@@ -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
index 8c80519..79543d7 100644 (file)
@@ -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);
index d2d44c2..684bc7c 100644 (file)
@@ -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
index 5e8b576..8e1eb0f 100644 (file)
@@ -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
 
index 7993ca2..9ea26de 100644 (file)
@@ -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;
index 31f8781..61236df 100644 (file)
@@ -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:
index 2bfe987..27d352a 100644 (file)
@@ -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