From 567db2c17d4ea8a0164d7abd8aed65b7a634bb40 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Fri, 12 Oct 2018 22:27:18 +0200 Subject: [PATCH] Add EVP_MAC API 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 (Merged from https://github.com/openssl/openssl/pull/7393) --- crypto/err/openssl.txt | 5 + crypto/evp/build.info | 3 +- crypto/evp/evp_err.c | 5 + crypto/evp/evp_locl.h | 5 + crypto/evp/mac_lib.c | 185 ++++++++++++++++ crypto/evp/names.c | 75 ++++++- crypto/include/internal/evp_int.h | 25 +++ doc/man3/EVP_MAC.pod | 348 ++++++++++++++++++++++++++++++ include/openssl/evp.h | 32 +++ include/openssl/evperr.h | 5 + include/openssl/objects.h | 3 +- include/openssl/ossl_typ.h | 2 + util/libcrypto.num | 18 ++ util/private.num | 5 + 14 files changed, 713 insertions(+), 3 deletions(-) create mode 100644 crypto/evp/mac_lib.c create mode 100644 doc/man3/EVP_MAC.pod 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 +#include +#include +#include +#include +#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 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 + + 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 is a type that holds the implementation of a MAC. + +B 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. +EVP_MAC_CTX_new_id() creates a new context for the numerical MAC +identity . +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 is a valid parameter, for which this function is a no-op. + +EVP_MAC_CTX_copy() makes a deep copy of the C context to the +C context. +The C context I have been created before calling this +function. + +EVP_MAC_CTX_mac() returns the B associated with the context +C. + +=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 bytes from C to the MAC input. + +EVP_MAC_final() does the final computation and stores the result in +the memory pointed at by C, and sets its size in the B +the C points at. +If C is B, then no computation is made. +To figure out what the output length will be and allocate space for it +dynamically, simply call with C being B and C +pointing at a valid location, then allocate space and make a second +call with C 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. +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 below for a description of standard controls. + +EVP_MAC_vctrl() is the variant of EVP_MAC_ctrl() that takes a +C argument instead of variadic arguments. + +EVP_MAC_ctrl_str() is an alternative to EVP_MAC_ctrl() to control the +MAC implementation as E C, C E 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 + +This control expects two arguments: C, C + +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 be set first, see B, +B and B below. + +=item B + +This control expects one arguments: C + +These will set the MAC flags to the given numbers. +Some MACs do not support this option. + +=item B + +=item B + +=item B + +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 takes one argument: C + +B takes one argument: C + +B takes one argument: C + +=item B + +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. + +EVP_MAC_name() returns the name for the given C, if it has been +added to the object database. + +EVP_add_mac() returns 1 if the given C 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. + +=head1 EXAMPLE + + #include + #include + #include + #include + #include + + #include + #include + + 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 and compiled to +F<./foo>) + +=head1 SEE ALSO + +=begin comment + +Add links to existing implementations in this form: + +L + +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. + +=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 + # include # include # include @@ -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 -- 2.25.1