mac.c revision 255767
1139790Simp/* $OpenBSD: mac.c,v 1.24 2013/06/03 00:03:18 dtucker Exp $ */ 2738Sache/* 34Srgrimes * Copyright (c) 2001 Markus Friedl. All rights reserved. 4738Sache * 5738Sache * Redistribution and use in source and binary forms, with or without 6106323Smdodd * modification, are permitted provided that the following conditions 74Srgrimes * are met: 84Srgrimes * 1. Redistributions of source code must retain the above copyright 9115703Sobrien * notice, this list of conditions and the following disclaimer. 10115703Sobrien * 2. Redistributions in binary form must reproduce the above copyright 11115703Sobrien * notice, this list of conditions and the following disclaimer in the 122056Swollman * documentation and/or other materials provided with the distribution. 132056Swollman * 142056Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1561994Smsmith * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 162056Swollman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1712675Sjulian * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1852843Sphk * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1960038Sphk * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 207090Sbde * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21152306Sru * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 224Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2312675Sjulian * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2412675Sjulian */ 2512675Sjulian 2612675Sjulian#include "includes.h" 2712502Sjulian 2847625Sphk#include <sys/types.h> 29126080Sphk 30126080Sphk#include <openssl/hmac.h> 31111815Sphk 32111815Sphk#include <stdarg.h> 33111815Sphk#include <string.h> 34111815Sphk#include <signal.h> 35111815Sphk 3647625Sphk#include "xmalloc.h" 3712675Sjulian#include "log.h" 3869774Sphk#include "cipher.h" 3960038Sphk#include "buffer.h" 40179004Sphk#include "key.h" 41179004Sphk#include "kex.h" 424Srgrimes#include "mac.h" 4319174Sbde#include "misc.h" 444Srgrimes 454Srgrimes#include "umac.h" 464Srgrimes 474Srgrimes#include "openbsd-compat/openssl-compat.h" 4819174Sbde 494Srgrimes#define SSH_EVP 1 /* OpenSSL EVP-based MAC */ 504Srgrimes#define SSH_UMAC 2 /* UMAC (not integrated with OpenSSL) */ 514Srgrimes#define SSH_UMAC128 3 524Srgrimes 53766Sachestruct macalg { 54766Sache char *name; 554Srgrimes int type; 56170278Sbrian const EVP_MD * (*mdfunc)(void); 57170278Sbrian int truncatebits; /* truncate digest if != 0 */ 5892765Salfred int key_len; /* just for UMAC */ 5992765Salfred int len; /* just for UMAC */ 6092765Salfred int etm; /* Encrypt-then-MAC */ 6112854Sbde}; 62179004Sphk 63179004Sphkstatic const struct macalg macs[] = { 64179004Sphk /* Encrypt-and-MAC (encrypt-and-authenticate) variants */ 6517232Sjoerg { "hmac-sha1", SSH_EVP, EVP_sha1, 0, 0, 0, 0 }, 66179004Sphk { "hmac-sha1-96", SSH_EVP, EVP_sha1, 96, 0, 0, 0 }, 674Srgrimes#ifdef HAVE_EVP_SHA256 68179004Sphk { "hmac-sha2-256", SSH_EVP, EVP_sha256, 0, 0, 0, 0 }, 694Srgrimes { "hmac-sha2-512", SSH_EVP, EVP_sha512, 0, 0, 0, 0 }, 70179004Sphk#endif 71179004Sphk { "hmac-md5", SSH_EVP, EVP_md5, 0, 0, 0, 0 }, 728288Sdg { "hmac-md5-96", SSH_EVP, EVP_md5, 96, 0, 0, 0 }, 734Srgrimes { "hmac-ripemd160", SSH_EVP, EVP_ripemd160, 0, 0, 0, 0 }, 74179004Sphk { "hmac-ripemd160@openssh.com", SSH_EVP, EVP_ripemd160, 0, 0, 0, 0 }, 754Srgrimes { "umac-64@openssh.com", SSH_UMAC, NULL, 0, 128, 64, 0 }, 764Srgrimes { "umac-128@openssh.com", SSH_UMAC128, NULL, 0, 128, 128, 0 }, 77179004Sphk 78179004Sphk /* Encrypt-then-MAC variants */ 791393Ssos { "hmac-sha1-etm@openssh.com", SSH_EVP, EVP_sha1, 0, 0, 0, 1 }, 80179004Sphk { "hmac-sha1-96-etm@openssh.com", SSH_EVP, EVP_sha1, 96, 0, 0, 1 }, 81179004Sphk#ifdef HAVE_EVP_SHA256 82179004Sphk { "hmac-sha2-256-etm@openssh.com", SSH_EVP, EVP_sha256, 0, 0, 0, 1 }, 83179004Sphk { "hmac-sha2-512-etm@openssh.com", SSH_EVP, EVP_sha512, 0, 0, 0, 1 }, 84179004Sphk#endif 8517232Sjoerg { "hmac-md5-etm@openssh.com", SSH_EVP, EVP_md5, 0, 0, 0, 1 }, 86179004Sphk { "hmac-md5-96-etm@openssh.com", SSH_EVP, EVP_md5, 96, 0, 0, 1 }, 87179004Sphk { "hmac-ripemd160-etm@openssh.com", SSH_EVP, EVP_ripemd160, 0, 0, 0, 1 }, 88179004Sphk { "umac-64-etm@openssh.com", SSH_UMAC, NULL, 0, 128, 64, 1 }, 894Srgrimes { "umac-128-etm@openssh.com", SSH_UMAC128, NULL, 0, 128, 128, 1 }, 90179004Sphk 91179004Sphk { NULL, 0, NULL, 0, 0, 0, 0 } 92179004Sphk}; 93179004Sphk 94179004Sphk/* Returns a comma-separated list of supported MACs. */ 95179004Sphkchar * 96179004Sphkmac_alg_list(void) 97179004Sphk{ 98179004Sphk char *ret = NULL; 99179004Sphk size_t nlen, rlen = 0; 100179004Sphk const struct macalg *m; 1014Srgrimes 1024Srgrimes for (m = macs; m->name != NULL; m++) { 103179004Sphk if (ret != NULL) 104179004Sphk ret[rlen++] = '\n'; 105179004Sphk nlen = strlen(m->name); 10617232Sjoerg ret = xrealloc(ret, 1, rlen + nlen + 2); 107179004Sphk memcpy(ret + rlen, m->name, nlen + 1); 1084Srgrimes rlen += nlen; 109179004Sphk } 110170278Sbrian return ret; 111179004Sphk} 112179004Sphk 113179004Sphkstatic void 114179004Sphkmac_setup_by_alg(Mac *mac, const struct macalg *macalg) 115179004Sphk{ 1164Srgrimes int evp_len; 117179004Sphk 1184Srgrimes mac->type = macalg->type; 119179004Sphk if (mac->type == SSH_EVP) { 120179004Sphk mac->evp_md = macalg->mdfunc(); 121179004Sphk if ((evp_len = EVP_MD_size(mac->evp_md)) <= 0) 1224Srgrimes fatal("mac %s len %d", mac->name, evp_len); 1234Srgrimes mac->key_len = mac->mac_len = (u_int)evp_len; 124179004Sphk } else { 125179004Sphk mac->mac_len = macalg->len / 8; 1264Srgrimes mac->key_len = macalg->key_len / 8; 127738Sache mac->umac_ctx = NULL; 128738Sache } 1294Srgrimes if (macalg->truncatebits != 0) 1304Srgrimes mac->mac_len = macalg->truncatebits / 8; 1314Srgrimes mac->etm = macalg->etm; 1324Srgrimes} 133229157Smdf 1344Srgrimesint 135229157Smdfmac_setup(Mac *mac, char *name) 1364Srgrimes{ 1374Srgrimes const struct macalg *m; 1384Srgrimes 1394Srgrimes for (m = macs; m->name != NULL; m++) { 1404Srgrimes if (strcmp(name, m->name) != 0) 1414Srgrimes continue; 1424Srgrimes if (mac != NULL) 1434Srgrimes mac_setup_by_alg(mac, m); 1444Srgrimes debug2("mac_setup: found %s", name); 1454Srgrimes return (0); 1464Srgrimes } 1474Srgrimes debug2("mac_setup: unknown %s", name); 1484Srgrimes return (-1); 1494Srgrimes} 1504Srgrimes 1514Srgrimesint 1524Srgrimesmac_init(Mac *mac) 1534Srgrimes{ 1544Srgrimes if (mac->key == NULL) 1554Srgrimes fatal("mac_init: no key"); 1564Srgrimes switch (mac->type) { 1574Srgrimes case SSH_EVP: 1584Srgrimes if (mac->evp_md == NULL) 1594Srgrimes return -1; 1604Srgrimes HMAC_CTX_init(&mac->evp_ctx); 1614Srgrimes HMAC_Init(&mac->evp_ctx, mac->key, mac->key_len, mac->evp_md); 1624Srgrimes return 0; 1634Srgrimes case SSH_UMAC: 1644Srgrimes mac->umac_ctx = umac_new(mac->key); 1654Srgrimes return 0; 1664Srgrimes case SSH_UMAC128: 1674Srgrimes mac->umac_ctx = umac128_new(mac->key); 1684Srgrimes return 0; 1694Srgrimes default: 1704Srgrimes return -1; 1714Srgrimes } 1724Srgrimes} 1734Srgrimes 1744Srgrimesu_char * 1754Srgrimesmac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen) 1764Srgrimes{ 1774Srgrimes static union { 1784Srgrimes u_char m[EVP_MAX_MD_SIZE]; 1794Srgrimes u_int64_t for_align; 1804Srgrimes } u; 1814Srgrimes u_char b[4], nonce[8]; 1824Srgrimes 1834Srgrimes if (mac->mac_len > sizeof(u)) 1844Srgrimes fatal("mac_compute: mac too long %u %lu", 1854Srgrimes mac->mac_len, (u_long)sizeof(u)); 1864Srgrimes 18717232Sjoerg switch (mac->type) { 18817232Sjoerg case SSH_EVP: 1894Srgrimes put_u32(b, seqno); 1904Srgrimes /* reset HMAC context */ 191170280Sbrian HMAC_Init(&mac->evp_ctx, NULL, 0, NULL); 1924Srgrimes HMAC_Update(&mac->evp_ctx, b, sizeof(b)); 1934Srgrimes HMAC_Update(&mac->evp_ctx, data, datalen); 1944Srgrimes HMAC_Final(&mac->evp_ctx, u.m, NULL); 1954Srgrimes break; 1964Srgrimes case SSH_UMAC: 1974Srgrimes put_u64(nonce, seqno); 198179004Sphk umac_update(mac->umac_ctx, data, datalen); 199179004Sphk umac_final(mac->umac_ctx, u.m, nonce); 200179004Sphk break; 20117232Sjoerg case SSH_UMAC128: 202179004Sphk put_u64(nonce, seqno); 2034Srgrimes umac128_update(mac->umac_ctx, data, datalen); 204179004Sphk umac128_final(mac->umac_ctx, u.m, nonce); 2054Srgrimes break; 206179004Sphk default: 207179004Sphk fatal("mac_compute: unknown MAC type"); 208179004Sphk } 209179004Sphk return (u.m); 210179004Sphk} 211179004Sphk 2124Srgrimesvoid 213179004Sphkmac_clear(Mac *mac) 214179004Sphk{ 2158288Sdg if (mac->type == SSH_UMAC) { 216179004Sphk if (mac->umac_ctx != NULL) 217179004Sphk umac_delete(mac->umac_ctx); 218179004Sphk } else if (mac->type == SSH_UMAC128) { 219179004Sphk if (mac->umac_ctx != NULL) 220179004Sphk umac128_delete(mac->umac_ctx); 221179004Sphk } else if (mac->evp_md != NULL) 2224Srgrimes HMAC_cleanup(&mac->evp_ctx); 2234Srgrimes mac->evp_md = NULL; 224179004Sphk mac->umac_ctx = NULL; 2254Srgrimes} 2264Srgrimes 2274Srgrimes/* XXX copied from ciphers_valid */ 228179004Sphk#define MAC_SEP "," 229179004Sphkint 230179004Sphkmac_valid(const char *names) 231179004Sphk{ 2324Srgrimes char *maclist, *cp, *p; 2334Srgrimes 234179004Sphk if (names == NULL || strcmp(names, "") == 0) 235179004Sphk return (0); 236179004Sphk maclist = cp = xstrdup(names); 23717232Sjoerg for ((p = strsep(&cp, MAC_SEP)); p && *p != '\0'; 238179004Sphk (p = strsep(&cp, MAC_SEP))) { 2394Srgrimes if (mac_setup(NULL, p) < 0) { 240179004Sphk debug("bad mac %s [%s]", p, names); 2414Srgrimes free(maclist); 2424Srgrimes return (0); 2434Srgrimes } else { 244179004Sphk debug3("mac ok: %s [%s]", p, names); 245179004Sphk } 246179004Sphk } 2474Srgrimes debug3("macs ok: [%s]", names); 2484Srgrimes free(maclist); 249179004Sphk return (1); 2504Srgrimes} 2514Srgrimes