isisd: implement MD5 circuit authentication

* Replace command "isis passwd" with "isis passwd {clear|md5}"
* Verify HMAC MD5 on ISIS Hello PDUs
* Add HMAC MD5 authentication to md5.h/md5.c from RFC2104
This commit is contained in:
Fritz Reichmann 2011-10-01 17:49:48 +04:00 committed by Denis Ovsienko
parent c25eaffdb2
commit e6b03b7776
8 changed files with 204 additions and 25 deletions

View file

@ -830,6 +830,21 @@ isis_interface_config_write (struct vty *vty)
}
}
}
if (c->passwd.type==ISIS_PASSWD_TYPE_HMAC_MD5)
{
vty_out (vty, " isis password md5 %s%s", c->passwd.passwd,
VTY_NEWLINE);
write++;
}
else
{
if (c->passwd.type==ISIS_PASSWD_TYPE_CLEARTXT)
{
vty_out (vty, " isis password clear %s%s", c->passwd.passwd,
VTY_NEWLINE);
write++;
}
}
}
}
@ -1022,11 +1037,44 @@ DEFUN (no_isis_circuit_type,
return CMD_SUCCESS;
}
DEFUN (isis_passwd,
isis_passwd_cmd,
"isis password WORD",
DEFUN (isis_passwd_md5,
isis_passwd_md5_cmd,
"isis password md5 WORD",
"IS-IS commands\n"
"Configure the authentication password for interface\n"
"Authentication Type\n"
"Password\n")
{
struct isis_circuit *circuit;
struct interface *ifp;
int len;
ifp = vty->index;
circuit = ifp->info;
if (circuit == NULL)
{
return CMD_WARNING;
}
len = strlen (argv[0]);
if (len > 254)
{
vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE);
return CMD_WARNING;
}
circuit->passwd.len = len;
circuit->passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5;
strncpy ((char *)circuit->passwd.passwd, argv[0], 255);
return CMD_SUCCESS;
}
DEFUN (isis_passwd_clear,
isis_passwd_clear_cmd,
"isis password clear WORD",
"IS-IS commands\n"
"Configure the authentication password for interface\n"
"Authentication Type\n"
"Password\n")
{
struct isis_circuit *circuit;
@ -1075,7 +1123,6 @@ DEFUN (no_isis_passwd,
return CMD_SUCCESS;
}
DEFUN (isis_priority,
isis_priority_cmd,
"isis priority <0-127>",
@ -2086,7 +2133,8 @@ isis_circuit_init ()
install_element (INTERFACE_NODE, &isis_circuit_type_cmd);
install_element (INTERFACE_NODE, &no_isis_circuit_type_cmd);
install_element (INTERFACE_NODE, &isis_passwd_cmd);
install_element (INTERFACE_NODE, &isis_passwd_clear_cmd);
install_element (INTERFACE_NODE, &isis_passwd_md5_cmd);
install_element (INTERFACE_NODE, &no_isis_passwd_cmd);
install_element (INTERFACE_NODE, &isis_priority_cmd);

View file

@ -35,6 +35,7 @@ struct isis_passwd
u_char len;
#define ISIS_PASSWD_TYPE_UNUSED 0
#define ISIS_PASSWD_TYPE_CLEARTXT 1
#define ISIS_PASSWD_TYPE_HMAC_MD5 54
#define ISIS_PASSWD_TYPE_PRIVATE 255
u_char type;
/* Authenticate SNPs? */

View file

@ -353,10 +353,25 @@ isis_lsp_authinfo_check (struct stream *stream, struct isis_area *area,
ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
pdulen - ISIS_FIXED_HDR_LEN
- ISIS_LSP_HDR_LEN, &expected, &found, &tlvs);
if (retval || !(found & TLVFLAG_AUTH_INFO))
return 1; /* Auth fail (parsing failed or no auth-tlv) */
return authentication_check (passwd, &tlvs.auth_info);
switch (tlvs.auth_info.type)
{
case ISIS_PASSWD_TYPE_HMAC_MD5:
zlog_debug("Got LSP with ISIS_PASSWD_TYPE_HMAC_MD5");
break;
case ISIS_PASSWD_TYPE_CLEARTXT:
zlog_debug("Got LSP with ISIS_PASSWD_TYPE_CLEARTXT");
break;
default:
zlog_debug("Unknown authentication type in LSP");
break;
}
return 0;
/* return authentication_check (passwd, &tlvs.auth_info);*/
}
static void

View file

@ -33,6 +33,7 @@
#include "prefix.h"
#include "if.h"
#include "checksum.h"
#include "md5.h"
#include "isisd/dict.h"
#include "isisd/include-netbsd/iso.h"
@ -168,26 +169,38 @@ accept_level (int level, int circuit_t)
return retval;
}
/*
* Verify authentication information
* Support cleartext and HMAC MD5 authentication
*/
int
authentication_check (struct isis_passwd *one, struct isis_passwd *theother)
authentication_check (struct isis_passwd *remote, struct isis_passwd *local, struct isis_circuit* c)
{
if (one->type != theother->type)
unsigned char digest[ISIS_AUTH_MD5_SIZE];
if (c->passwd.type)
{
zlog_warn ("Unsupported authentication type %d", theother->type);
return 1; /* Auth fail (different authentication types) */
}
switch (one->type)
switch (c->passwd.type)
{
case ISIS_PASSWD_TYPE_HMAC_MD5:
/* HMAC MD5 (RFC 3567) */
/* MD5 computation according to RFC 2104 */
hmac_md5(c->rcv_stream->data, stream_get_endp(c->rcv_stream), (unsigned char *) &(local->passwd), c->passwd.len, (unsigned char *) &digest);
return memcmp (digest, remote->passwd, ISIS_AUTH_MD5_SIZE);
break;
case ISIS_PASSWD_TYPE_CLEARTXT:
if (one->len != theother->len)
/* Cleartext (ISO 10589) */
if (local->len != remote->len)
return 1; /* Auth fail () - passwd len mismatch */
return memcmp (one->passwd, theother->passwd, one->len);
return memcmp (local->passwd, remote->passwd, local->len);
break;
default:
zlog_warn ("Unsupported authentication type");
break;
}
return 0; /* Auth pass */
}
return 0; /* Authentication pass when no authentication is configured */
}
/*
@ -372,7 +385,7 @@ process_p2p_hello (struct isis_circuit *circuit)
if (circuit->passwd.type)
{
if (!(found & TLVFLAG_AUTH_INFO) ||
authentication_check (&circuit->passwd, &tlvs.auth_info))
authentication_check (&tlvs.auth_info, &circuit->passwd, circuit))
{
isis_event_auth_failure (circuit->area->area_tag,
"P2P hello authentication failure",
@ -744,10 +757,11 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)
goto out;
}
/* Verify authentication, either cleartext of HMAC MD5 */
if (circuit->passwd.type)
{
if (!(found & TLVFLAG_AUTH_INFO) ||
authentication_check (&circuit->passwd, &tlvs.auth_info))
authentication_check (&tlvs.auth_info, &circuit->passwd, circuit))
{
isis_event_auth_failure (circuit->area->area_tag,
"LAN hello authentication failure",
@ -1416,7 +1430,7 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,
if (passwd->type)
{
if (!(found & TLVFLAG_AUTH_INFO) ||
authentication_check (passwd, &tlvs.auth_info))
authentication_check (&tlvs.auth_info, passwd, circuit))
{
isis_event_auth_failure (circuit->area->area_tag,
"SNP authentication" " failure",
@ -1913,9 +1927,10 @@ send_hello (struct isis_circuit *circuit, int level)
struct isis_fixed_hdr fixed_hdr;
struct isis_lan_hello_hdr hello_hdr;
struct isis_p2p_hello_hdr p2p_hello_hdr;
char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
u_int32_t interval;
unsigned long len_pointer, length;
unsigned long len_pointer, length, auth_tlv;
int retval;
if (circuit->state != C_STATE_UP || circuit->interface == NULL)
@ -1987,12 +2002,25 @@ send_hello (struct isis_circuit *circuit, int level)
/*
* Then the variable length part
*/
/* add circuit password */
if (circuit->passwd.type)
if (tlv_add_authinfo (circuit->passwd.type, circuit->passwd.len,
/* Cleartext */
if (circuit->passwd.type == ISIS_PASSWD_TYPE_CLEARTXT)
if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, circuit->passwd.len,
circuit->passwd.passwd, circuit->snd_stream))
return ISIS_WARNING;
/* or HMAC MD5 */
if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
{
/* Remember where TLV is written so we can later overwrite the MD5 hash */
auth_tlv = stream_get_endp (circuit->snd_stream);
memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE,
hmac_md5_hash, circuit->snd_stream))
return ISIS_WARNING;
}
/* Protocols Supported TLV */
if (circuit->nlpids.count > 0)
if (tlv_add_nlpid (&circuit->nlpids, circuit->snd_stream))
@ -2041,6 +2069,14 @@ send_hello (struct isis_circuit *circuit, int level)
/* Update PDU length */
stream_putw_at (circuit->snd_stream, len_pointer, (u_int16_t) length);
/* For HMAC MD5 we need to compute the md5 hash and store it */
if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
{
hmac_md5(circuit->snd_stream->data, stream_get_endp(circuit->snd_stream), (unsigned char *) &circuit->passwd.passwd, circuit->passwd.len, (unsigned char *) &hmac_md5_hash);
/* Copy the hash into the stream */
memcpy(circuit->snd_stream->data+auth_tlv+3,hmac_md5_hash,ISIS_AUTH_MD5_SIZE);
}
retval = circuit->tx (circuit, level);
if (retval)
zlog_warn ("sending of LAN Level %d Hello failed", level);

View file

@ -258,8 +258,7 @@ int ack_lsp (struct isis_link_state_hdr *hdr,
void fill_fixed_hdr (struct isis_fixed_hdr *hdr, u_char pdu_type);
int send_hello (struct isis_circuit *circuit, int level);
int authentication_check (struct isis_passwd *one,
struct isis_passwd *theother);
#define ISIS_AUTH_MD5_SIZE 16U
int authentication_check (struct isis_passwd *remote, struct isis_passwd *local, struct isis_circuit *c);
#endif /* _ZEBRA_ISIS_PDU_H */

View file

@ -446,6 +446,10 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
tlvs->auth_info.len = length-1;
pnt++;
memcpy (tlvs->auth_info.passwd, pnt, length - 1);
/* Fill authentication with 0 for later computation
* of MD5 (RFC 5304, 2)
*/
memset (pnt, 0, length - 1);
pnt += length - 1;
}
else
@ -878,7 +882,7 @@ tlv_add_authinfo (char auth_type, char auth_len, u_char *auth_value,
{
u_char value[255];
u_char *pos = value;
*pos++ = ISIS_PASSWD_TYPE_CLEARTXT;
*pos++ = auth_type;
memcpy (pos, auth_value, auth_len);
return add_tlv (AUTH_INFO, auth_len + 1, value, stream);

View file

@ -298,3 +298,76 @@ static void md5_calc(const uint8_t *b64, md5_ctxt * ctxt)
ctxt->md5_stc += C;
ctxt->md5_std += D;
}
/* From RFC 2104 */
void
hmac_md5(text, text_len, key, key_len, digest)
unsigned char* text; /* pointer to data stream */
int text_len; /* length of data stream */
unsigned char* key; /* pointer to authentication key */
int key_len; /* length of authentication key */
caddr_t digest; /* caller digest to be filled in */
{
MD5_CTX context;
unsigned char k_ipad[65]; /* inner padding -
* key XORd with ipad
*/
unsigned char k_opad[65]; /* outer padding -
* key XORd with opad
*/
unsigned char tk[16];
int i;
/* if key is longer than 64 bytes reset it to key=MD5(key) */
if (key_len > 64) {
MD5_CTX tctx;
MD5Init(&tctx);
MD5Update(&tctx, key, key_len);
MD5Final(tk, &tctx);
key = tk;
key_len = 16;
}
/*
* the HMAC_MD5 transform looks like:
*
* MD5(K XOR opad, MD5(K XOR ipad, text))
*
* where K is an n byte key
* ipad is the byte 0x36 repeated 64 times
* opad is the byte 0x5c repeated 64 times
* and text is the data being protected
*/
/* start out by storing key in pads */
bzero( k_ipad, sizeof k_ipad);
bzero( k_opad, sizeof k_opad);
bcopy( key, k_ipad, key_len);
bcopy( key, k_opad, key_len);
/* XOR key with ipad and opad values */
for (i=0; i<64; i++) {
k_ipad[i] ^= 0x36;
k_opad[i] ^= 0x5c;
}
/*
* perform inner MD5
*/
MD5Init(&context); /* init context for 1st
* pass */
MD5Update(&context, k_ipad, 64); /* start with inner pad */
MD5Update(&context, text, text_len); /* then text of datagram */
MD5Final(digest, &context); /* finish up 1st pass */
/*
* perform outer MD5
*/
MD5Init(&context); /* init context for 2nd
* pass */
MD5Update(&context, k_opad, 64); /* start with outer pad */
MD5Update(&context, digest, 16); /* then results of 1st
* hash */
MD5Final(digest, &context); /* finish up 2nd pass */
}

View file

@ -82,4 +82,7 @@ do { \
md5_result((x), (y)); \
} while (0)
/* From RFC 2104 */
void hmac_md5(unsigned char* text, int text_len, unsigned char* key, int key_len, caddr_t digest);
#endif /* ! _LIBZEBRA_MD5_H_*/