Home | History | Annotate | Download | only in openssh
      1 /* $OpenBSD: mac.c,v 1.16 2011/08/02 01:22:11 djm Exp $ */
      2 /*
      3  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "includes.h"
     27 
     28 #include <sys/types.h>
     29 
     30 #include <openssl/hmac.h>
     31 
     32 #include <stdarg.h>
     33 #include <string.h>
     34 #include <signal.h>
     35 
     36 #include "xmalloc.h"
     37 #include "log.h"
     38 #include "cipher.h"
     39 #include "buffer.h"
     40 #include "key.h"
     41 #include "kex.h"
     42 #include "mac.h"
     43 #include "misc.h"
     44 
     45 #include "umac.h"
     46 
     47 #define SSH_EVP		1	/* OpenSSL EVP-based MAC */
     48 #define SSH_UMAC	2	/* UMAC (not integrated with OpenSSL) */
     49 
     50 struct {
     51 	char		*name;
     52 	int		type;
     53 	const EVP_MD *	(*mdfunc)(void);
     54 	int		truncatebits;	/* truncate digest if != 0 */
     55 	int		key_len;	/* just for UMAC */
     56 	int		len;		/* just for UMAC */
     57 } macs[] = {
     58 	{ "hmac-sha1",			SSH_EVP, EVP_sha1, 0, -1, -1 },
     59 	{ "hmac-sha1-96",		SSH_EVP, EVP_sha1, 96, -1, -1 },
     60 #ifdef HAVE_EVP_SHA256
     61 	{ "hmac-sha2-256",		SSH_EVP, EVP_sha256, 0, -1, -1 },
     62 	{ "hmac-sha2-256-96",		SSH_EVP, EVP_sha256, 96, -1, -1 },
     63 	{ "hmac-sha2-512",		SSH_EVP, EVP_sha512, 0, -1, -1 },
     64 	{ "hmac-sha2-512-96",		SSH_EVP, EVP_sha512, 96, -1, -1 },
     65 #endif
     66 	{ "hmac-md5",			SSH_EVP, EVP_md5, 0, -1, -1 },
     67 	{ "hmac-md5-96",		SSH_EVP, EVP_md5, 96, -1, -1 },
     68 	{ "hmac-ripemd160",		SSH_EVP, EVP_ripemd160, 0, -1, -1 },
     69 	{ "hmac-ripemd160 (at) openssh.com",	SSH_EVP, EVP_ripemd160, 0, -1, -1 },
     70 	{ "umac-64 (at) openssh.com",	SSH_UMAC, NULL, 0, 128, 64 },
     71 	{ NULL,				0, NULL, 0, -1, -1 }
     72 };
     73 
     74 static void
     75 mac_setup_by_id(Mac *mac, int which)
     76 {
     77 	int evp_len;
     78 	mac->type = macs[which].type;
     79 	if (mac->type == SSH_EVP) {
     80 		mac->evp_md = (*macs[which].mdfunc)();
     81 		if ((evp_len = EVP_MD_size(mac->evp_md)) <= 0)
     82 			fatal("mac %s len %d", mac->name, evp_len);
     83 		mac->key_len = mac->mac_len = (u_int)evp_len;
     84 	} else {
     85 		mac->mac_len = macs[which].len / 8;
     86 		mac->key_len = macs[which].key_len / 8;
     87 		mac->umac_ctx = NULL;
     88 	}
     89 	if (macs[which].truncatebits != 0)
     90 		mac->mac_len = macs[which].truncatebits / 8;
     91 }
     92 
     93 int
     94 mac_setup(Mac *mac, char *name)
     95 {
     96 	int i;
     97 
     98 	for (i = 0; macs[i].name; i++) {
     99 		if (strcmp(name, macs[i].name) == 0) {
    100 			if (mac != NULL)
    101 				mac_setup_by_id(mac, i);
    102 			debug2("mac_setup: found %s", name);
    103 			return (0);
    104 		}
    105 	}
    106 	debug2("mac_setup: unknown %s", name);
    107 	return (-1);
    108 }
    109 
    110 int
    111 mac_init(Mac *mac)
    112 {
    113 	if (mac->key == NULL)
    114 		fatal("mac_init: no key");
    115 	switch (mac->type) {
    116 	case SSH_EVP:
    117 		if (mac->evp_md == NULL)
    118 			return -1;
    119 		HMAC_Init(&mac->evp_ctx, mac->key, mac->key_len, mac->evp_md);
    120 		return 0;
    121 	case SSH_UMAC:
    122 		mac->umac_ctx = umac_new(mac->key);
    123 		return 0;
    124 	default:
    125 		return -1;
    126 	}
    127 }
    128 
    129 u_char *
    130 mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen)
    131 {
    132 	static u_char m[EVP_MAX_MD_SIZE];
    133 	u_char b[4], nonce[8];
    134 
    135 	if (mac->mac_len > sizeof(m))
    136 		fatal("mac_compute: mac too long %u %lu",
    137 		    mac->mac_len, (u_long)sizeof(m));
    138 
    139 	switch (mac->type) {
    140 	case SSH_EVP:
    141 		put_u32(b, seqno);
    142 		/* reset HMAC context */
    143 		HMAC_Init(&mac->evp_ctx, NULL, 0, NULL);
    144 		HMAC_Update(&mac->evp_ctx, b, sizeof(b));
    145 		HMAC_Update(&mac->evp_ctx, data, datalen);
    146 		HMAC_Final(&mac->evp_ctx, m, NULL);
    147 		break;
    148 	case SSH_UMAC:
    149 		put_u64(nonce, seqno);
    150 		umac_update(mac->umac_ctx, data, datalen);
    151 		umac_final(mac->umac_ctx, m, nonce);
    152 		break;
    153 	default:
    154 		fatal("mac_compute: unknown MAC type");
    155 	}
    156 	return (m);
    157 }
    158 
    159 void
    160 mac_clear(Mac *mac)
    161 {
    162 	if (mac->type == SSH_UMAC) {
    163 		if (mac->umac_ctx != NULL)
    164 			umac_delete(mac->umac_ctx);
    165 	} else if (mac->evp_md != NULL)
    166 		HMAC_cleanup(&mac->evp_ctx);
    167 	mac->evp_md = NULL;
    168 	mac->umac_ctx = NULL;
    169 }
    170 
    171 /* XXX copied from ciphers_valid */
    172 #define	MAC_SEP	","
    173 int
    174 mac_valid(const char *names)
    175 {
    176 	char *maclist, *cp, *p;
    177 
    178 	if (names == NULL || strcmp(names, "") == 0)
    179 		return (0);
    180 	maclist = cp = xstrdup(names);
    181 	for ((p = strsep(&cp, MAC_SEP)); p && *p != '\0';
    182 	    (p = strsep(&cp, MAC_SEP))) {
    183 		if (mac_setup(NULL, p) < 0) {
    184 			debug("bad mac %s [%s]", p, names);
    185 			xfree(maclist);
    186 			return (0);
    187 		} else {
    188 			debug3("mac ok: %s [%s]", p, names);
    189 		}
    190 	}
    191 	debug3("macs ok: [%s]", names);
    192 	xfree(maclist);
    193 	return (1);
    194 }
    195