version 1.13, 2007/06/05 06:52:37 |
version 1.14, 2007/06/07 19:37:34 |
|
|
#include "mac.h" |
#include "mac.h" |
#include "misc.h" |
#include "misc.h" |
|
|
|
#include "umac.h" |
|
|
|
#define SSH_EVP 1 /* OpenSSL EVP-based MAC */ |
|
#define SSH_UMAC 2 /* UMAC (not integrated with OpenSSL) */ |
|
|
struct { |
struct { |
char *name; |
char *name; |
|
int type; |
const EVP_MD * (*mdfunc)(void); |
const EVP_MD * (*mdfunc)(void); |
int truncatebits; /* truncate digest if != 0 */ |
int truncatebits; /* truncate digest if != 0 */ |
|
int key_len; /* just for UMAC */ |
|
int len; /* just for UMAC */ |
} macs[] = { |
} macs[] = { |
{ "hmac-sha1", EVP_sha1, 0, }, |
{ "hmac-sha1", SSH_EVP, EVP_sha1, 0, -1, -1 }, |
{ "hmac-sha1-96", EVP_sha1, 96 }, |
{ "hmac-sha1-96", SSH_EVP, EVP_sha1, 96, -1, -1 }, |
{ "hmac-md5", EVP_md5, 0 }, |
{ "hmac-md5", SSH_EVP, EVP_md5, 0, -1, -1 }, |
{ "hmac-md5-96", EVP_md5, 96 }, |
{ "hmac-md5-96", SSH_EVP, EVP_md5, 96, -1, -1 }, |
{ "hmac-ripemd160", EVP_ripemd160, 0 }, |
{ "hmac-ripemd160", SSH_EVP, EVP_ripemd160, 0, -1, -1 }, |
{ "hmac-ripemd160@openssh.com", EVP_ripemd160, 0 }, |
{ "hmac-ripemd160@openssh.com", SSH_EVP, EVP_ripemd160, 0, -1, -1 }, |
{ NULL, NULL, 0 } |
{ "umac-64@openssh.com", SSH_UMAC, NULL, 0, 128, 64 }, |
|
{ NULL, 0, NULL, 0, -1, -1 } |
}; |
}; |
|
|
|
static void |
|
mac_setup_by_id(Mac *mac, int which) |
|
{ |
|
int evp_len; |
|
mac->type = macs[which].type; |
|
if (mac->type == SSH_EVP) { |
|
mac->evp_md = (*macs[which].mdfunc)(); |
|
if ((evp_len = EVP_MD_size(mac->evp_md)) <= 0) |
|
fatal("mac %s len %d", mac->name, evp_len); |
|
mac->key_len = mac->mac_len = (u_int)evp_len; |
|
} else { |
|
mac->mac_len = macs[which].len / 8; |
|
mac->key_len = macs[which].key_len / 8; |
|
mac->umac_ctx = NULL; |
|
} |
|
if (macs[which].truncatebits != 0) |
|
mac->mac_len = macs[which].truncatebits / 8; |
|
} |
|
|
int |
int |
mac_setup(Mac *mac, char *name) |
mac_setup(Mac *mac, char *name) |
{ |
{ |
int i, evp_len; |
int i; |
|
|
for (i = 0; macs[i].name; i++) { |
for (i = 0; macs[i].name; i++) { |
if (strcmp(name, macs[i].name) == 0) { |
if (strcmp(name, macs[i].name) == 0) { |
if (mac != NULL) { |
if (mac != NULL) |
mac->md = (*macs[i].mdfunc)(); |
mac_setup_by_id(mac, i); |
if ((evp_len = EVP_MD_size(mac->md)) <= 0) |
|
fatal("mac %s len %d", name, evp_len); |
|
mac->key_len = mac->mac_len = (u_int)evp_len; |
|
if (macs[i].truncatebits != 0) |
|
mac->mac_len = macs[i].truncatebits/8; |
|
} |
|
debug2("mac_setup: found %s", name); |
debug2("mac_setup: found %s", name); |
return (0); |
return (0); |
} |
} |
|
|
return (-1); |
return (-1); |
} |
} |
|
|
void |
int |
mac_init(Mac *mac) |
mac_init(Mac *mac) |
{ |
{ |
if (mac->key == NULL) |
if (mac->key == NULL) |
fatal("mac_init: no key"); |
fatal("mac_init: no key"); |
HMAC_Init(&mac->ctx, mac->key, mac->key_len, mac->md); |
switch (mac->type) { |
|
case SSH_EVP: |
|
if (mac->evp_md == NULL) |
|
return -1; |
|
HMAC_Init(&mac->evp_ctx, mac->key, mac->key_len, mac->evp_md); |
|
return 0; |
|
case SSH_UMAC: |
|
mac->umac_ctx = umac_new(mac->key); |
|
return 0; |
|
default: |
|
return -1; |
|
} |
} |
} |
|
|
u_char * |
u_char * |
mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen) |
mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen) |
{ |
{ |
static u_char m[EVP_MAX_MD_SIZE]; |
static u_char m[EVP_MAX_MD_SIZE]; |
u_char b[4]; |
u_char b[4], nonce[8]; |
|
|
if (mac->mac_len > sizeof(m)) |
if (mac->mac_len > sizeof(m)) |
fatal("mac_compute: mac too long"); |
fatal("mac_compute: mac too long %u %lu", |
put_u32(b, seqno); |
mac->mac_len, sizeof(m)); |
HMAC_Init(&mac->ctx, NULL, 0, NULL); /* reset HMAC context */ |
|
HMAC_Update(&mac->ctx, b, sizeof(b)); |
switch (mac->type) { |
HMAC_Update(&mac->ctx, data, datalen); |
case SSH_EVP: |
HMAC_Final(&mac->ctx, m, NULL); |
put_u32(b, seqno); |
|
/* reset HMAC context */ |
|
HMAC_Init(&mac->evp_ctx, NULL, 0, NULL); |
|
HMAC_Update(&mac->evp_ctx, b, sizeof(b)); |
|
HMAC_Update(&mac->evp_ctx, data, datalen); |
|
HMAC_Final(&mac->evp_ctx, m, NULL); |
|
break; |
|
case SSH_UMAC: |
|
put_u64(nonce, seqno); |
|
umac_update(mac->umac_ctx, data, datalen); |
|
umac_final(mac->umac_ctx, m, nonce); |
|
break; |
|
default: |
|
fatal("mac_compute: unknown MAC type"); |
|
} |
return (m); |
return (m); |
} |
} |
|
|
void |
void |
mac_clear(Mac *mac) |
mac_clear(Mac *mac) |
{ |
{ |
HMAC_cleanup(&mac->ctx); |
if (mac->type == SSH_UMAC) { |
|
if (mac->umac_ctx != NULL) |
|
umac_delete(mac->umac_ctx); |
|
} else if (mac->evp_md != NULL) |
|
HMAC_cleanup(&mac->evp_ctx); |
|
mac->evp_md = NULL; |
|
mac->umac_ctx = NULL; |
} |
} |
|
|
/* XXX copied from ciphers_valid */ |
/* XXX copied from ciphers_valid */ |