forked from Mirror/frr
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:
parent
c25eaffdb2
commit
e6b03b7776
|
@ -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;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFUN (isis_passwd,
|
DEFUN (isis_passwd_md5,
|
||||||
isis_passwd_cmd,
|
isis_passwd_md5_cmd,
|
||||||
"isis password WORD",
|
"isis password md5 WORD",
|
||||||
"IS-IS commands\n"
|
"IS-IS commands\n"
|
||||||
"Configure the authentication password for interface\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")
|
"Password\n")
|
||||||
{
|
{
|
||||||
struct isis_circuit *circuit;
|
struct isis_circuit *circuit;
|
||||||
|
@ -1075,7 +1123,6 @@ DEFUN (no_isis_passwd,
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DEFUN (isis_priority,
|
DEFUN (isis_priority,
|
||||||
isis_priority_cmd,
|
isis_priority_cmd,
|
||||||
"isis priority <0-127>",
|
"isis priority <0-127>",
|
||||||
|
@ -2086,7 +2133,8 @@ isis_circuit_init ()
|
||||||
install_element (INTERFACE_NODE, &isis_circuit_type_cmd);
|
install_element (INTERFACE_NODE, &isis_circuit_type_cmd);
|
||||||
install_element (INTERFACE_NODE, &no_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, &no_isis_passwd_cmd);
|
||||||
|
|
||||||
install_element (INTERFACE_NODE, &isis_priority_cmd);
|
install_element (INTERFACE_NODE, &isis_priority_cmd);
|
||||||
|
|
|
@ -35,6 +35,7 @@ struct isis_passwd
|
||||||
u_char len;
|
u_char len;
|
||||||
#define ISIS_PASSWD_TYPE_UNUSED 0
|
#define ISIS_PASSWD_TYPE_UNUSED 0
|
||||||
#define ISIS_PASSWD_TYPE_CLEARTXT 1
|
#define ISIS_PASSWD_TYPE_CLEARTXT 1
|
||||||
|
#define ISIS_PASSWD_TYPE_HMAC_MD5 54
|
||||||
#define ISIS_PASSWD_TYPE_PRIVATE 255
|
#define ISIS_PASSWD_TYPE_PRIVATE 255
|
||||||
u_char type;
|
u_char type;
|
||||||
/* Authenticate SNPs? */
|
/* Authenticate SNPs? */
|
||||||
|
|
|
@ -353,10 +353,25 @@ isis_lsp_authinfo_check (struct stream *stream, struct isis_area *area,
|
||||||
ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
|
ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
|
||||||
pdulen - ISIS_FIXED_HDR_LEN
|
pdulen - ISIS_FIXED_HDR_LEN
|
||||||
- ISIS_LSP_HDR_LEN, &expected, &found, &tlvs);
|
- ISIS_LSP_HDR_LEN, &expected, &found, &tlvs);
|
||||||
|
|
||||||
if (retval || !(found & TLVFLAG_AUTH_INFO))
|
if (retval || !(found & TLVFLAG_AUTH_INFO))
|
||||||
return 1; /* Auth fail (parsing failed or no auth-tlv) */
|
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
|
static void
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "prefix.h"
|
#include "prefix.h"
|
||||||
#include "if.h"
|
#include "if.h"
|
||||||
#include "checksum.h"
|
#include "checksum.h"
|
||||||
|
#include "md5.h"
|
||||||
|
|
||||||
#include "isisd/dict.h"
|
#include "isisd/dict.h"
|
||||||
#include "isisd/include-netbsd/iso.h"
|
#include "isisd/include-netbsd/iso.h"
|
||||||
|
@ -168,26 +169,38 @@ accept_level (int level, int circuit_t)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify authentication information
|
||||||
|
* Support cleartext and HMAC MD5 authentication
|
||||||
|
*/
|
||||||
int
|
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);
|
switch (c->passwd.type)
|
||||||
return 1; /* Auth fail (different authentication types) */
|
|
||||||
}
|
|
||||||
switch (one->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:
|
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 1; /* Auth fail () - passwd len mismatch */
|
||||||
return memcmp (one->passwd, theother->passwd, one->len);
|
return memcmp (local->passwd, remote->passwd, local->len);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
zlog_warn ("Unsupported authentication type");
|
zlog_warn ("Unsupported authentication type");
|
||||||
break;
|
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 (circuit->passwd.type)
|
||||||
{
|
{
|
||||||
if (!(found & TLVFLAG_AUTH_INFO) ||
|
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,
|
isis_event_auth_failure (circuit->area->area_tag,
|
||||||
"P2P hello authentication failure",
|
"P2P hello authentication failure",
|
||||||
|
@ -744,10 +757,11 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Verify authentication, either cleartext of HMAC MD5 */
|
||||||
if (circuit->passwd.type)
|
if (circuit->passwd.type)
|
||||||
{
|
{
|
||||||
if (!(found & TLVFLAG_AUTH_INFO) ||
|
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,
|
isis_event_auth_failure (circuit->area->area_tag,
|
||||||
"LAN hello authentication failure",
|
"LAN hello authentication failure",
|
||||||
|
@ -1416,7 +1430,7 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,
|
||||||
if (passwd->type)
|
if (passwd->type)
|
||||||
{
|
{
|
||||||
if (!(found & TLVFLAG_AUTH_INFO) ||
|
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,
|
isis_event_auth_failure (circuit->area->area_tag,
|
||||||
"SNP authentication" " failure",
|
"SNP authentication" " failure",
|
||||||
|
@ -1913,9 +1927,10 @@ send_hello (struct isis_circuit *circuit, int level)
|
||||||
struct isis_fixed_hdr fixed_hdr;
|
struct isis_fixed_hdr fixed_hdr;
|
||||||
struct isis_lan_hello_hdr hello_hdr;
|
struct isis_lan_hello_hdr hello_hdr;
|
||||||
struct isis_p2p_hello_hdr p2p_hello_hdr;
|
struct isis_p2p_hello_hdr p2p_hello_hdr;
|
||||||
|
char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
|
||||||
|
|
||||||
u_int32_t interval;
|
u_int32_t interval;
|
||||||
unsigned long len_pointer, length;
|
unsigned long len_pointer, length, auth_tlv;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (circuit->state != C_STATE_UP || circuit->interface == NULL)
|
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
|
* Then the variable length part
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* add circuit password */
|
/* add circuit password */
|
||||||
if (circuit->passwd.type)
|
/* Cleartext */
|
||||||
if (tlv_add_authinfo (circuit->passwd.type, circuit->passwd.len,
|
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))
|
circuit->passwd.passwd, circuit->snd_stream))
|
||||||
return ISIS_WARNING;
|
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 */
|
/* Protocols Supported TLV */
|
||||||
if (circuit->nlpids.count > 0)
|
if (circuit->nlpids.count > 0)
|
||||||
if (tlv_add_nlpid (&circuit->nlpids, circuit->snd_stream))
|
if (tlv_add_nlpid (&circuit->nlpids, circuit->snd_stream))
|
||||||
|
@ -2041,6 +2069,14 @@ send_hello (struct isis_circuit *circuit, int level)
|
||||||
/* Update PDU length */
|
/* Update PDU length */
|
||||||
stream_putw_at (circuit->snd_stream, len_pointer, (u_int16_t) 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);
|
retval = circuit->tx (circuit, level);
|
||||||
if (retval)
|
if (retval)
|
||||||
zlog_warn ("sending of LAN Level %d Hello failed", level);
|
zlog_warn ("sending of LAN Level %d Hello failed", level);
|
||||||
|
|
|
@ -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);
|
void fill_fixed_hdr (struct isis_fixed_hdr *hdr, u_char pdu_type);
|
||||||
int send_hello (struct isis_circuit *circuit, int level);
|
int send_hello (struct isis_circuit *circuit, int level);
|
||||||
|
|
||||||
|
#define ISIS_AUTH_MD5_SIZE 16U
|
||||||
int authentication_check (struct isis_passwd *one,
|
int authentication_check (struct isis_passwd *remote, struct isis_passwd *local, struct isis_circuit *c);
|
||||||
struct isis_passwd *theother);
|
|
||||||
|
|
||||||
#endif /* _ZEBRA_ISIS_PDU_H */
|
#endif /* _ZEBRA_ISIS_PDU_H */
|
||||||
|
|
|
@ -446,6 +446,10 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
|
||||||
tlvs->auth_info.len = length-1;
|
tlvs->auth_info.len = length-1;
|
||||||
pnt++;
|
pnt++;
|
||||||
memcpy (tlvs->auth_info.passwd, pnt, length - 1);
|
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;
|
pnt += length - 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -878,7 +882,7 @@ tlv_add_authinfo (char auth_type, char auth_len, u_char *auth_value,
|
||||||
{
|
{
|
||||||
u_char value[255];
|
u_char value[255];
|
||||||
u_char *pos = value;
|
u_char *pos = value;
|
||||||
*pos++ = ISIS_PASSWD_TYPE_CLEARTXT;
|
*pos++ = auth_type;
|
||||||
memcpy (pos, auth_value, auth_len);
|
memcpy (pos, auth_value, auth_len);
|
||||||
|
|
||||||
return add_tlv (AUTH_INFO, auth_len + 1, value, stream);
|
return add_tlv (AUTH_INFO, auth_len + 1, value, stream);
|
||||||
|
|
73
lib/md5.c
73
lib/md5.c
|
@ -298,3 +298,76 @@ static void md5_calc(const uint8_t *b64, md5_ctxt * ctxt)
|
||||||
ctxt->md5_stc += C;
|
ctxt->md5_stc += C;
|
||||||
ctxt->md5_std += D;
|
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 */
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue