mac.c revision 181111
155714Skris/* $OpenBSD: mac.c,v 1.15 2008/06/13 00:51:47 dtucker Exp $ */ 255714Skris/* 355714Skris * Copyright (c) 2001 Markus Friedl. All rights reserved. 455714Skris * 555714Skris * Redistribution and use in source and binary forms, with or without 655714Skris * modification, are permitted provided that the following conditions 755714Skris * are met: 855714Skris * 1. Redistributions of source code must retain the above copyright 955714Skris * notice, this list of conditions and the following disclaimer. 1055714Skris * 2. Redistributions in binary form must reproduce the above copyright 1155714Skris * notice, this list of conditions and the following disclaimer in the 1255714Skris * documentation and/or other materials provided with the distribution. 1355714Skris * 1455714Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1555714Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1655714Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1755714Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1855714Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1955714Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2055714Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2155714Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2255714Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2355714Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2455714Skris */ 2555714Skris 2655714Skris#include "includes.h" 2755714Skris 2855714Skris#include <sys/types.h> 2955714Skris 3055714Skris#include <openssl/hmac.h> 3155714Skris 3255714Skris#include <stdarg.h> 3355714Skris#include <string.h> 3455714Skris#include <signal.h> 3555714Skris 3655714Skris#include "xmalloc.h" 3755714Skris#include "log.h" 3855714Skris#include "cipher.h" 3955714Skris#include "buffer.h" 4055714Skris#include "key.h" 4155714Skris#include "kex.h" 4255714Skris#include "mac.h" 4355714Skris#include "misc.h" 4455714Skris 4555714Skris#include "umac.h" 4655714Skris 4755714Skris#define SSH_EVP 1 /* OpenSSL EVP-based MAC */ 4855714Skris#define SSH_UMAC 2 /* UMAC (not integrated with OpenSSL) */ 4955714Skris 5055714Skrisstruct { 5155714Skris char *name; 5255714Skris int type; 5355714Skris const EVP_MD * (*mdfunc)(void); 5455714Skris int truncatebits; /* truncate digest if != 0 */ 5555714Skris int key_len; /* just for UMAC */ 5655714Skris int len; /* just for UMAC */ 5755714Skris} macs[] = { 5855714Skris { "hmac-sha1", SSH_EVP, EVP_sha1, 0, -1, -1 }, 5955714Skris { "hmac-sha1-96", SSH_EVP, EVP_sha1, 96, -1, -1 }, 6055714Skris { "hmac-md5", SSH_EVP, EVP_md5, 0, -1, -1 }, 6155714Skris { "hmac-md5-96", SSH_EVP, EVP_md5, 96, -1, -1 }, 6255714Skris { "hmac-ripemd160", SSH_EVP, EVP_ripemd160, 0, -1, -1 }, 6355714Skris { "hmac-ripemd160@openssh.com", SSH_EVP, EVP_ripemd160, 0, -1, -1 }, 6455714Skris { "umac-64@openssh.com", SSH_UMAC, NULL, 0, 128, 64 }, 6555714Skris { NULL, 0, NULL, 0, -1, -1 } 6655714Skris}; 6755714Skris 6855714Skrisstatic void 6955714Skrismac_setup_by_id(Mac *mac, int which) 7055714Skris{ 7155714Skris int evp_len; 7255714Skris mac->type = macs[which].type; 7355714Skris if (mac->type == SSH_EVP) { 7455714Skris mac->evp_md = (*macs[which].mdfunc)(); 7555714Skris if ((evp_len = EVP_MD_size(mac->evp_md)) <= 0) 7655714Skris fatal("mac %s len %d", mac->name, evp_len); 7755714Skris mac->key_len = mac->mac_len = (u_int)evp_len; 7855714Skris } else { 7955714Skris mac->mac_len = macs[which].len / 8; 8055714Skris mac->key_len = macs[which].key_len / 8; 8155714Skris mac->umac_ctx = NULL; 8255714Skris } 8355714Skris if (macs[which].truncatebits != 0) 8455714Skris mac->mac_len = macs[which].truncatebits / 8; 8555714Skris} 8655714Skris 8755714Skrisint 8855714Skrismac_setup(Mac *mac, char *name) 8955714Skris{ 9055714Skris int i; 9155714Skris 9255714Skris for (i = 0; macs[i].name; i++) { 9355714Skris if (strcmp(name, macs[i].name) == 0) { 9455714Skris if (mac != NULL) 9555714Skris mac_setup_by_id(mac, i); 9655714Skris debug2("mac_setup: found %s", name); 9755714Skris return (0); 9855714Skris } 9955714Skris } 10055714Skris debug2("mac_setup: unknown %s", name); 10155714Skris return (-1); 10255714Skris} 10355714Skris 10455714Skrisint 10555714Skrismac_init(Mac *mac) 10655714Skris{ 10755714Skris if (mac->key == NULL) 10855714Skris fatal("mac_init: no key"); 10955714Skris switch (mac->type) { 11055714Skris case SSH_EVP: 11155714Skris if (mac->evp_md == NULL) 11255714Skris return -1; 11355714Skris HMAC_Init(&mac->evp_ctx, mac->key, mac->key_len, mac->evp_md); 11455714Skris return 0; 11555714Skris case SSH_UMAC: 11655714Skris mac->umac_ctx = umac_new(mac->key); 11755714Skris return 0; 11855714Skris default: 11955714Skris return -1; 12055714Skris } 12155714Skris} 12255714Skris 12355714Skrisu_char * 12455714Skrismac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen) 12555714Skris{ 12655714Skris static u_char m[EVP_MAX_MD_SIZE]; 12755714Skris u_char b[4], nonce[8]; 12855714Skris 12955714Skris if (mac->mac_len > sizeof(m)) 13055714Skris fatal("mac_compute: mac too long %u %lu", 13155714Skris mac->mac_len, (u_long)sizeof(m)); 13255714Skris 13355714Skris switch (mac->type) { 13455714Skris case SSH_EVP: 13555714Skris put_u32(b, seqno); 13655714Skris /* reset HMAC context */ 13755714Skris HMAC_Init(&mac->evp_ctx, NULL, 0, NULL); 13855714Skris HMAC_Update(&mac->evp_ctx, b, sizeof(b)); 13955714Skris HMAC_Update(&mac->evp_ctx, data, datalen); 14055714Skris HMAC_Final(&mac->evp_ctx, m, NULL); 14155714Skris break; 14255714Skris case SSH_UMAC: 14355714Skris put_u64(nonce, seqno); 14455714Skris umac_update(mac->umac_ctx, data, datalen); 14555714Skris umac_final(mac->umac_ctx, m, nonce); 14655714Skris break; 14755714Skris default: 14855714Skris fatal("mac_compute: unknown MAC type"); 14955714Skris } 15055714Skris return (m); 15155714Skris} 15255714Skris 15355714Skrisvoid 15455714Skrismac_clear(Mac *mac) 15555714Skris{ 15655714Skris if (mac->type == SSH_UMAC) { 15755714Skris if (mac->umac_ctx != NULL) 15855714Skris umac_delete(mac->umac_ctx); 15955714Skris } else if (mac->evp_md != NULL) 16055714Skris HMAC_cleanup(&mac->evp_ctx); 16155714Skris mac->evp_md = NULL; 16255714Skris mac->umac_ctx = NULL; 16355714Skris} 16455714Skris 16555714Skris/* XXX copied from ciphers_valid */ 16655714Skris#define MAC_SEP "," 16755714Skrisint 16855714Skrismac_valid(const char *names) 16955714Skris{ 17055714Skris char *maclist, *cp, *p; 17155714Skris 17255714Skris if (names == NULL || strcmp(names, "") == 0) 17355714Skris return (0); 17455714Skris maclist = cp = xstrdup(names); 17555714Skris for ((p = strsep(&cp, MAC_SEP)); p && *p != '\0'; 17655714Skris (p = strsep(&cp, MAC_SEP))) { 17755714Skris if (mac_setup(NULL, p) < 0) { 17855714Skris debug("bad mac %s [%s]", p, names); 17955714Skris xfree(maclist); 18055714Skris return (0); 18155714Skris } else { 18255714Skris debug3("mac ok: %s [%s]", p, names); 18355714Skris } 18455714Skris } 18555714Skris debug3("macs ok: [%s]", names); 18655714Skris xfree(maclist); 18755714Skris return (1); 18855714Skris} 18955714Skris