1255767Sdes/* $OpenBSD: mac.c,v 1.24 2013/06/03 00:03:18 dtucker Exp $ */ 276259Sgreen/* 376259Sgreen * Copyright (c) 2001 Markus Friedl. All rights reserved. 476259Sgreen * 576259Sgreen * Redistribution and use in source and binary forms, with or without 676259Sgreen * modification, are permitted provided that the following conditions 776259Sgreen * are met: 876259Sgreen * 1. Redistributions of source code must retain the above copyright 976259Sgreen * notice, this list of conditions and the following disclaimer. 1076259Sgreen * 2. Redistributions in binary form must reproduce the above copyright 1176259Sgreen * notice, this list of conditions and the following disclaimer in the 1276259Sgreen * documentation and/or other materials provided with the distribution. 1376259Sgreen * 1476259Sgreen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1576259Sgreen * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1676259Sgreen * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1776259Sgreen * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1876259Sgreen * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1976259Sgreen * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2076259Sgreen * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2176259Sgreen * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2276259Sgreen * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2376259Sgreen * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2476259Sgreen */ 2576259Sgreen 2676259Sgreen#include "includes.h" 2776259Sgreen 28162852Sdes#include <sys/types.h> 29162852Sdes 3076259Sgreen#include <openssl/hmac.h> 3176259Sgreen 32162852Sdes#include <stdarg.h> 33162852Sdes#include <string.h> 34162852Sdes#include <signal.h> 35162852Sdes 3676259Sgreen#include "xmalloc.h" 3776259Sgreen#include "log.h" 3876259Sgreen#include "cipher.h" 39162852Sdes#include "buffer.h" 40162852Sdes#include "key.h" 4176259Sgreen#include "kex.h" 4276259Sgreen#include "mac.h" 43162852Sdes#include "misc.h" 4476259Sgreen 45181111Sdes#include "umac.h" 46181111Sdes 47240075Sdes#include "openbsd-compat/openssl-compat.h" 48240075Sdes 49181111Sdes#define SSH_EVP 1 /* OpenSSL EVP-based MAC */ 50181111Sdes#define SSH_UMAC 2 /* UMAC (not integrated with OpenSSL) */ 51248619Sdes#define SSH_UMAC128 3 52181111Sdes 53255767Sdesstruct macalg { 5476259Sgreen char *name; 55181111Sdes int type; 5698675Sdes const EVP_MD * (*mdfunc)(void); 5776259Sgreen int truncatebits; /* truncate digest if != 0 */ 58181111Sdes int key_len; /* just for UMAC */ 59181111Sdes int len; /* just for UMAC */ 60248619Sdes int etm; /* Encrypt-then-MAC */ 61255767Sdes}; 62255767Sdes 63255767Sdesstatic const struct macalg macs[] = { 64248619Sdes /* Encrypt-and-MAC (encrypt-and-authenticate) variants */ 65248619Sdes { "hmac-sha1", SSH_EVP, EVP_sha1, 0, 0, 0, 0 }, 66248619Sdes { "hmac-sha1-96", SSH_EVP, EVP_sha1, 96, 0, 0, 0 }, 67226046Sdes#ifdef HAVE_EVP_SHA256 68248619Sdes { "hmac-sha2-256", SSH_EVP, EVP_sha256, 0, 0, 0, 0 }, 69248619Sdes { "hmac-sha2-512", SSH_EVP, EVP_sha512, 0, 0, 0, 0 }, 70226046Sdes#endif 71248619Sdes { "hmac-md5", SSH_EVP, EVP_md5, 0, 0, 0, 0 }, 72248619Sdes { "hmac-md5-96", SSH_EVP, EVP_md5, 96, 0, 0, 0 }, 73248619Sdes { "hmac-ripemd160", SSH_EVP, EVP_ripemd160, 0, 0, 0, 0 }, 74248619Sdes { "hmac-ripemd160@openssh.com", SSH_EVP, EVP_ripemd160, 0, 0, 0, 0 }, 75248619Sdes { "umac-64@openssh.com", SSH_UMAC, NULL, 0, 128, 64, 0 }, 76248619Sdes { "umac-128@openssh.com", SSH_UMAC128, NULL, 0, 128, 128, 0 }, 77248619Sdes 78248619Sdes /* Encrypt-then-MAC variants */ 79248619Sdes { "hmac-sha1-etm@openssh.com", SSH_EVP, EVP_sha1, 0, 0, 0, 1 }, 80248619Sdes { "hmac-sha1-96-etm@openssh.com", SSH_EVP, EVP_sha1, 96, 0, 0, 1 }, 81248619Sdes#ifdef HAVE_EVP_SHA256 82248619Sdes { "hmac-sha2-256-etm@openssh.com", SSH_EVP, EVP_sha256, 0, 0, 0, 1 }, 83248619Sdes { "hmac-sha2-512-etm@openssh.com", SSH_EVP, EVP_sha512, 0, 0, 0, 1 }, 84248619Sdes#endif 85248619Sdes { "hmac-md5-etm@openssh.com", SSH_EVP, EVP_md5, 0, 0, 0, 1 }, 86248619Sdes { "hmac-md5-96-etm@openssh.com", SSH_EVP, EVP_md5, 96, 0, 0, 1 }, 87248619Sdes { "hmac-ripemd160-etm@openssh.com", SSH_EVP, EVP_ripemd160, 0, 0, 0, 1 }, 88248619Sdes { "umac-64-etm@openssh.com", SSH_UMAC, NULL, 0, 128, 64, 1 }, 89248619Sdes { "umac-128-etm@openssh.com", SSH_UMAC128, NULL, 0, 128, 128, 1 }, 90248619Sdes 91248619Sdes { NULL, 0, NULL, 0, 0, 0, 0 } 9276259Sgreen}; 9376259Sgreen 94255767Sdes/* Returns a comma-separated list of supported MACs. */ 95255767Sdeschar * 96255767Sdesmac_alg_list(void) 97255767Sdes{ 98255767Sdes char *ret = NULL; 99255767Sdes size_t nlen, rlen = 0; 100255767Sdes const struct macalg *m; 101255767Sdes 102255767Sdes for (m = macs; m->name != NULL; m++) { 103255767Sdes if (ret != NULL) 104255767Sdes ret[rlen++] = '\n'; 105255767Sdes nlen = strlen(m->name); 106255767Sdes ret = xrealloc(ret, 1, rlen + nlen + 2); 107255767Sdes memcpy(ret + rlen, m->name, nlen + 1); 108255767Sdes rlen += nlen; 109255767Sdes } 110255767Sdes return ret; 111255767Sdes} 112255767Sdes 113181111Sdesstatic void 114255767Sdesmac_setup_by_alg(Mac *mac, const struct macalg *macalg) 115181111Sdes{ 116181111Sdes int evp_len; 117255767Sdes 118255767Sdes mac->type = macalg->type; 119181111Sdes if (mac->type == SSH_EVP) { 120255767Sdes mac->evp_md = macalg->mdfunc(); 121181111Sdes if ((evp_len = EVP_MD_size(mac->evp_md)) <= 0) 122181111Sdes fatal("mac %s len %d", mac->name, evp_len); 123181111Sdes mac->key_len = mac->mac_len = (u_int)evp_len; 124181111Sdes } else { 125255767Sdes mac->mac_len = macalg->len / 8; 126255767Sdes mac->key_len = macalg->key_len / 8; 127181111Sdes mac->umac_ctx = NULL; 128181111Sdes } 129255767Sdes if (macalg->truncatebits != 0) 130255767Sdes mac->mac_len = macalg->truncatebits / 8; 131255767Sdes mac->etm = macalg->etm; 132181111Sdes} 133181111Sdes 13476259Sgreenint 135181111Sdesmac_setup(Mac *mac, char *name) 13676259Sgreen{ 137255767Sdes const struct macalg *m; 138149749Sdes 139255767Sdes for (m = macs; m->name != NULL; m++) { 140255767Sdes if (strcmp(name, m->name) != 0) 141255767Sdes continue; 142255767Sdes if (mac != NULL) 143255767Sdes mac_setup_by_alg(mac, m); 144255767Sdes debug2("mac_setup: found %s", name); 145255767Sdes return (0); 14676259Sgreen } 147181111Sdes debug2("mac_setup: unknown %s", name); 14876259Sgreen return (-1); 14976259Sgreen} 15076259Sgreen 151181111Sdesint 152181111Sdesmac_init(Mac *mac) 153181111Sdes{ 154181111Sdes if (mac->key == NULL) 155181111Sdes fatal("mac_init: no key"); 156181111Sdes switch (mac->type) { 157181111Sdes case SSH_EVP: 158181111Sdes if (mac->evp_md == NULL) 159181111Sdes return -1; 160240075Sdes HMAC_CTX_init(&mac->evp_ctx); 161181111Sdes HMAC_Init(&mac->evp_ctx, mac->key, mac->key_len, mac->evp_md); 162181111Sdes return 0; 163181111Sdes case SSH_UMAC: 164181111Sdes mac->umac_ctx = umac_new(mac->key); 165181111Sdes return 0; 166248619Sdes case SSH_UMAC128: 167248619Sdes mac->umac_ctx = umac128_new(mac->key); 168248619Sdes return 0; 169181111Sdes default: 170181111Sdes return -1; 171181111Sdes } 172181111Sdes} 173181111Sdes 17476259Sgreenu_char * 17576259Sgreenmac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen) 17676259Sgreen{ 177255767Sdes static union { 178255767Sdes u_char m[EVP_MAX_MD_SIZE]; 179255767Sdes u_int64_t for_align; 180255767Sdes } u; 181181111Sdes u_char b[4], nonce[8]; 18276259Sgreen 183255767Sdes if (mac->mac_len > sizeof(u)) 184181111Sdes fatal("mac_compute: mac too long %u %lu", 185255767Sdes mac->mac_len, (u_long)sizeof(u)); 186181111Sdes 187181111Sdes switch (mac->type) { 188181111Sdes case SSH_EVP: 189181111Sdes put_u32(b, seqno); 190181111Sdes /* reset HMAC context */ 191181111Sdes HMAC_Init(&mac->evp_ctx, NULL, 0, NULL); 192181111Sdes HMAC_Update(&mac->evp_ctx, b, sizeof(b)); 193181111Sdes HMAC_Update(&mac->evp_ctx, data, datalen); 194255767Sdes HMAC_Final(&mac->evp_ctx, u.m, NULL); 195181111Sdes break; 196181111Sdes case SSH_UMAC: 197181111Sdes put_u64(nonce, seqno); 198181111Sdes umac_update(mac->umac_ctx, data, datalen); 199255767Sdes umac_final(mac->umac_ctx, u.m, nonce); 200181111Sdes break; 201248619Sdes case SSH_UMAC128: 202248619Sdes put_u64(nonce, seqno); 203248619Sdes umac128_update(mac->umac_ctx, data, datalen); 204255767Sdes umac128_final(mac->umac_ctx, u.m, nonce); 205248619Sdes break; 206181111Sdes default: 207181111Sdes fatal("mac_compute: unknown MAC type"); 208181111Sdes } 209255767Sdes return (u.m); 21076259Sgreen} 21176259Sgreen 212181111Sdesvoid 213181111Sdesmac_clear(Mac *mac) 214181111Sdes{ 215181111Sdes if (mac->type == SSH_UMAC) { 216181111Sdes if (mac->umac_ctx != NULL) 217181111Sdes umac_delete(mac->umac_ctx); 218248619Sdes } else if (mac->type == SSH_UMAC128) { 219248619Sdes if (mac->umac_ctx != NULL) 220248619Sdes umac128_delete(mac->umac_ctx); 221181111Sdes } else if (mac->evp_md != NULL) 222181111Sdes HMAC_cleanup(&mac->evp_ctx); 223181111Sdes mac->evp_md = NULL; 224181111Sdes mac->umac_ctx = NULL; 225181111Sdes} 226181111Sdes 22776259Sgreen/* XXX copied from ciphers_valid */ 22876259Sgreen#define MAC_SEP "," 22976259Sgreenint 23076259Sgreenmac_valid(const char *names) 23176259Sgreen{ 23276259Sgreen char *maclist, *cp, *p; 23376259Sgreen 23476259Sgreen if (names == NULL || strcmp(names, "") == 0) 23576259Sgreen return (0); 23676259Sgreen maclist = cp = xstrdup(names); 23776259Sgreen for ((p = strsep(&cp, MAC_SEP)); p && *p != '\0'; 23892555Sdes (p = strsep(&cp, MAC_SEP))) { 239181111Sdes if (mac_setup(NULL, p) < 0) { 24076259Sgreen debug("bad mac %s [%s]", p, names); 241255767Sdes free(maclist); 24276259Sgreen return (0); 24376259Sgreen } else { 24476259Sgreen debug3("mac ok: %s [%s]", p, names); 24576259Sgreen } 24676259Sgreen } 24776259Sgreen debug3("macs ok: [%s]", names); 248255767Sdes free(maclist); 24976259Sgreen return (1); 25076259Sgreen} 251