1323129Sdes/* $OpenBSD: mac.c,v 1.33 2016/07/08 03:44:42 djm 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 30162852Sdes#include <string.h> 31294332Sdes#include <stdio.h> 32162852Sdes 33263712Sdes#include "digest.h" 34263712Sdes#include "hmac.h" 35181111Sdes#include "umac.h" 36294332Sdes#include "mac.h" 37294332Sdes#include "misc.h" 38294332Sdes#include "ssherr.h" 39294332Sdes#include "sshbuf.h" 40181111Sdes 41240075Sdes#include "openbsd-compat/openssl-compat.h" 42240075Sdes 43263712Sdes#define SSH_DIGEST 1 /* SSH_DIGEST_XXX */ 44181111Sdes#define SSH_UMAC 2 /* UMAC (not integrated with OpenSSL) */ 45248619Sdes#define SSH_UMAC128 3 46181111Sdes 47255767Sdesstruct macalg { 4876259Sgreen char *name; 49181111Sdes int type; 50263712Sdes int alg; 5176259Sgreen int truncatebits; /* truncate digest if != 0 */ 52181111Sdes int key_len; /* just for UMAC */ 53181111Sdes int len; /* just for UMAC */ 54248619Sdes int etm; /* Encrypt-then-MAC */ 55255767Sdes}; 56255767Sdes 57255767Sdesstatic const struct macalg macs[] = { 58248619Sdes /* Encrypt-and-MAC (encrypt-and-authenticate) variants */ 59263712Sdes { "hmac-sha1", SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 0 }, 60263712Sdes { "hmac-sha1-96", SSH_DIGEST, SSH_DIGEST_SHA1, 96, 0, 0, 0 }, 61226046Sdes#ifdef HAVE_EVP_SHA256 62263712Sdes { "hmac-sha2-256", SSH_DIGEST, SSH_DIGEST_SHA256, 0, 0, 0, 0 }, 63263712Sdes { "hmac-sha2-512", SSH_DIGEST, SSH_DIGEST_SHA512, 0, 0, 0, 0 }, 64226046Sdes#endif 65263712Sdes { "hmac-md5", SSH_DIGEST, SSH_DIGEST_MD5, 0, 0, 0, 0 }, 66263712Sdes { "hmac-md5-96", SSH_DIGEST, SSH_DIGEST_MD5, 96, 0, 0, 0 }, 67323134Sdes#ifdef HAVE_EVP_RIPEMD160 68263712Sdes { "hmac-ripemd160", SSH_DIGEST, SSH_DIGEST_RIPEMD160, 0, 0, 0, 0 }, 69263712Sdes { "hmac-ripemd160@openssh.com", SSH_DIGEST, SSH_DIGEST_RIPEMD160, 0, 0, 0, 0 }, 70323134Sdes#endif 71263712Sdes { "umac-64@openssh.com", SSH_UMAC, 0, 0, 128, 64, 0 }, 72263712Sdes { "umac-128@openssh.com", SSH_UMAC128, 0, 0, 128, 128, 0 }, 73248619Sdes 74248619Sdes /* Encrypt-then-MAC variants */ 75263712Sdes { "hmac-sha1-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 1 }, 76263712Sdes { "hmac-sha1-96-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA1, 96, 0, 0, 1 }, 77248619Sdes#ifdef HAVE_EVP_SHA256 78263712Sdes { "hmac-sha2-256-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA256, 0, 0, 0, 1 }, 79263712Sdes { "hmac-sha2-512-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA512, 0, 0, 0, 1 }, 80248619Sdes#endif 81263712Sdes { "hmac-md5-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_MD5, 0, 0, 0, 1 }, 82263712Sdes { "hmac-md5-96-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_MD5, 96, 0, 0, 1 }, 83323134Sdes#ifdef HAVE_EVP_RIPEMD160 84263712Sdes { "hmac-ripemd160-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_RIPEMD160, 0, 0, 0, 1 }, 85323134Sdes#endif 86263712Sdes { "umac-64-etm@openssh.com", SSH_UMAC, 0, 0, 128, 64, 1 }, 87263712Sdes { "umac-128-etm@openssh.com", SSH_UMAC128, 0, 0, 128, 128, 1 }, 88248619Sdes 89263712Sdes { NULL, 0, 0, 0, 0, 0, 0 } 9076259Sgreen}; 9176259Sgreen 92261320Sdes/* Returns a list of supported MACs separated by the specified char. */ 93255767Sdeschar * 94261320Sdesmac_alg_list(char sep) 95255767Sdes{ 96294332Sdes char *ret = NULL, *tmp; 97255767Sdes size_t nlen, rlen = 0; 98255767Sdes const struct macalg *m; 99255767Sdes 100255767Sdes for (m = macs; m->name != NULL; m++) { 101255767Sdes if (ret != NULL) 102261320Sdes ret[rlen++] = sep; 103255767Sdes nlen = strlen(m->name); 104294332Sdes if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { 105294332Sdes free(ret); 106294332Sdes return NULL; 107294332Sdes } 108294332Sdes ret = tmp; 109255767Sdes memcpy(ret + rlen, m->name, nlen + 1); 110255767Sdes rlen += nlen; 111255767Sdes } 112255767Sdes return ret; 113255767Sdes} 114255767Sdes 115294332Sdesstatic int 116294332Sdesmac_setup_by_alg(struct sshmac *mac, const struct macalg *macalg) 117181111Sdes{ 118255767Sdes mac->type = macalg->type; 119263712Sdes if (mac->type == SSH_DIGEST) { 120263712Sdes if ((mac->hmac_ctx = ssh_hmac_start(macalg->alg)) == NULL) 121294332Sdes return SSH_ERR_ALLOC_FAIL; 122263712Sdes mac->key_len = mac->mac_len = ssh_hmac_bytes(macalg->alg); 123181111Sdes } else { 124255767Sdes mac->mac_len = macalg->len / 8; 125255767Sdes mac->key_len = macalg->key_len / 8; 126181111Sdes mac->umac_ctx = NULL; 127181111Sdes } 128255767Sdes if (macalg->truncatebits != 0) 129255767Sdes mac->mac_len = macalg->truncatebits / 8; 130255767Sdes mac->etm = macalg->etm; 131294332Sdes return 0; 132181111Sdes} 133181111Sdes 13476259Sgreenint 135294332Sdesmac_setup(struct sshmac *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; 142294332Sdes if (mac != NULL) 143294332Sdes return mac_setup_by_alg(mac, m); 144294332Sdes return 0; 14576259Sgreen } 146294332Sdes return SSH_ERR_INVALID_ARGUMENT; 14776259Sgreen} 14876259Sgreen 149181111Sdesint 150294332Sdesmac_init(struct sshmac *mac) 151181111Sdes{ 152181111Sdes if (mac->key == NULL) 153294332Sdes return SSH_ERR_INVALID_ARGUMENT; 154181111Sdes switch (mac->type) { 155263712Sdes case SSH_DIGEST: 156263712Sdes if (mac->hmac_ctx == NULL || 157263712Sdes ssh_hmac_init(mac->hmac_ctx, mac->key, mac->key_len) < 0) 158294332Sdes return SSH_ERR_INVALID_ARGUMENT; 159181111Sdes return 0; 160181111Sdes case SSH_UMAC: 161294332Sdes if ((mac->umac_ctx = umac_new(mac->key)) == NULL) 162294332Sdes return SSH_ERR_ALLOC_FAIL; 163181111Sdes return 0; 164248619Sdes case SSH_UMAC128: 165294332Sdes if ((mac->umac_ctx = umac128_new(mac->key)) == NULL) 166294332Sdes return SSH_ERR_ALLOC_FAIL; 167248619Sdes return 0; 168181111Sdes default: 169294332Sdes return SSH_ERR_INVALID_ARGUMENT; 170181111Sdes } 171181111Sdes} 172181111Sdes 173294332Sdesint 174323129Sdesmac_compute(struct sshmac *mac, u_int32_t seqno, 175323129Sdes const u_char *data, int datalen, 176294332Sdes u_char *digest, size_t dlen) 17776259Sgreen{ 178255767Sdes static union { 179294332Sdes u_char m[SSH_DIGEST_MAX_LENGTH]; 180255767Sdes u_int64_t for_align; 181255767Sdes } u; 182294328Sdes u_char b[4]; 183294328Sdes u_char nonce[8]; 18476259Sgreen 185255767Sdes if (mac->mac_len > sizeof(u)) 186294332Sdes return SSH_ERR_INTERNAL_ERROR; 187181111Sdes 188181111Sdes switch (mac->type) { 189263712Sdes case SSH_DIGEST: 190181111Sdes put_u32(b, seqno); 191181111Sdes /* reset HMAC context */ 192263712Sdes if (ssh_hmac_init(mac->hmac_ctx, NULL, 0) < 0 || 193263712Sdes ssh_hmac_update(mac->hmac_ctx, b, sizeof(b)) < 0 || 194263712Sdes ssh_hmac_update(mac->hmac_ctx, data, datalen) < 0 || 195263712Sdes ssh_hmac_final(mac->hmac_ctx, u.m, sizeof(u.m)) < 0) 196294332Sdes return SSH_ERR_LIBCRYPTO_ERROR; 197181111Sdes break; 198181111Sdes case SSH_UMAC: 199294332Sdes POKE_U64(nonce, seqno); 200181111Sdes umac_update(mac->umac_ctx, data, datalen); 201255767Sdes umac_final(mac->umac_ctx, u.m, nonce); 202181111Sdes break; 203248619Sdes case SSH_UMAC128: 204248619Sdes put_u64(nonce, seqno); 205248619Sdes umac128_update(mac->umac_ctx, data, datalen); 206255767Sdes umac128_final(mac->umac_ctx, u.m, nonce); 207248619Sdes break; 208181111Sdes default: 209294332Sdes return SSH_ERR_INVALID_ARGUMENT; 210181111Sdes } 211294332Sdes if (digest != NULL) { 212294332Sdes if (dlen > mac->mac_len) 213294332Sdes dlen = mac->mac_len; 214294332Sdes memcpy(digest, u.m, dlen); 215294332Sdes } 216294332Sdes return 0; 21776259Sgreen} 21876259Sgreen 219323129Sdesint 220323129Sdesmac_check(struct sshmac *mac, u_int32_t seqno, 221323129Sdes const u_char *data, size_t dlen, 222323129Sdes const u_char *theirmac, size_t mlen) 223323129Sdes{ 224323129Sdes u_char ourmac[SSH_DIGEST_MAX_LENGTH]; 225323129Sdes int r; 226323129Sdes 227323129Sdes if (mac->mac_len > mlen) 228323129Sdes return SSH_ERR_INVALID_ARGUMENT; 229323129Sdes if ((r = mac_compute(mac, seqno, data, dlen, 230323129Sdes ourmac, sizeof(ourmac))) != 0) 231323129Sdes return r; 232323129Sdes if (timingsafe_bcmp(ourmac, theirmac, mac->mac_len) != 0) 233323129Sdes return SSH_ERR_MAC_INVALID; 234323129Sdes return 0; 235323129Sdes} 236323129Sdes 237181111Sdesvoid 238294332Sdesmac_clear(struct sshmac *mac) 239181111Sdes{ 240181111Sdes if (mac->type == SSH_UMAC) { 241181111Sdes if (mac->umac_ctx != NULL) 242181111Sdes umac_delete(mac->umac_ctx); 243248619Sdes } else if (mac->type == SSH_UMAC128) { 244248619Sdes if (mac->umac_ctx != NULL) 245248619Sdes umac128_delete(mac->umac_ctx); 246263712Sdes } else if (mac->hmac_ctx != NULL) 247263712Sdes ssh_hmac_free(mac->hmac_ctx); 248263712Sdes mac->hmac_ctx = NULL; 249181111Sdes mac->umac_ctx = NULL; 250181111Sdes} 251181111Sdes 25276259Sgreen/* XXX copied from ciphers_valid */ 25376259Sgreen#define MAC_SEP "," 25476259Sgreenint 25576259Sgreenmac_valid(const char *names) 25676259Sgreen{ 25776259Sgreen char *maclist, *cp, *p; 25876259Sgreen 25976259Sgreen if (names == NULL || strcmp(names, "") == 0) 260294332Sdes return 0; 261294332Sdes if ((maclist = cp = strdup(names)) == NULL) 262294332Sdes return 0; 26376259Sgreen for ((p = strsep(&cp, MAC_SEP)); p && *p != '\0'; 26492555Sdes (p = strsep(&cp, MAC_SEP))) { 265181111Sdes if (mac_setup(NULL, p) < 0) { 266255767Sdes free(maclist); 267294332Sdes return 0; 26876259Sgreen } 26976259Sgreen } 270255767Sdes free(maclist); 271294332Sdes return 1; 27276259Sgreen} 273