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
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c
index dfc613c..d67df31 100644
--- a/isisd/isis_pdu.c
+++ b/isisd/isis_pdu.c
@@ -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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/*
* 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 @@
/* 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);