[quagga-dev 10858] #PERSONAL#Re: Re: RFC-6506(Supporting Authentication Trailer for OSPFv3) implementation in quagga-0.99.21 version

Jyotsna Priya1 jyotsna.priya1 at tcs.com
Fri Oct 25 13:52:06 BST 2013


Hi Renato/List,

We are back with next revision of patch.

>You are looking for the AT bit in all
>received OSPFv3 packets, even the ones that don't have the Options
>field. You should look for the AT bit only on 'Hello' and 'Database
>Description' packets and store this information on the
>'ospf6_neighbor' structure. For other types of OSPFv3 packets, you
>should check if authentication is in use by looking for the previously
>stored information on the 'ospf6_neighbor' structure.

The problem has been fixed. A new variable has been introduced in neighbor data structure which stores information about the AT bit of hello and db packet.

>Your patch misses a lot of byte order macros, it won't work at all on any little endian machine;

We have made some changes in the code but more inputs are required from your side. Can you please mention some of the lines where the code misses byte order macros? Moreover we have tested the code on x86 little endian machines and its working fine.

>All your references to IP_STR should not be there;

The reference to IP_STR has been removed.

>The changes to the 'memtypes.h' and 'configure' files should not be
>in the patch since these are auto-generated files

The changes to memtypes.h has been removed. Only the changes for memtypes.c is included in the patch. As far as configure file is concerned, the changes are required to include the libgcrypt library which is used by sha algorithms.

>Your code has some stylistic issues like very long lines and
>improper indentation.

This issue has been resolved.


The inline patch is as follows:

diff -upwbNr quagga-0.99.21/configure quagga-rfc6506/configure
--- quagga-0.99.21/configure	2012-05-02 02:18:02.000000000 +0530
+++ quagga-rfc6506/configure	2013-07-11 15:04:54.000000000 +0530
@@ -642,6 +642,10 @@ PILDFLAGS
 PICFLAGS
 CONFDATE
 LIBCAP
+HAVE_LIBGCRYPT
+LIBGCRYPT_LIBS
+LIBGCRYPT_CFLAGS
+LIBGCRYPT_CONFIG
 SNMP_INCLUDES
 LIB_REGEX
 HAVE_LIBPCREPOSIX
@@ -857,6 +861,7 @@ enable_broken_aliases
 with_crypto
 enable_snmp
 with_libpam
+with_libgcrypt
 enable_tcp_zebra
 enable_opaque_lsa
 enable_ospfapi
@@ -878,6 +883,7 @@ enable_gcc_rdynamic
 enable_time_check
 enable_pcreposix
 enable_largefile
+with_libgcrypt_prefix
 enable_pie
 '
       ac_precious_vars='build_alias
@@ -1572,6 +1578,9 @@ Optional Packages:
                         (or the compiler's sysroot if not specified).
   --without-crypto        do not use libcrypto in SNMP
   --with-libpam           use libpam for PAM support in vtysh
+  --with-libgcrypt        use gcrypt library for crypto functions
+  --with-libgcrypt-prefix=PFX
+                          prefix where LIBGCRYPT is installed (optional)
 
 Some influential environment variables:
   GAWK        GNU AWK
@@ -3936,6 +3945,8 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_
 #include <stdarg.h>
 #include <stdio.h>
 struct stat;
+#include <sys/types.h>
+#include <sys/stat.h>
 /* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
 struct buf { int x; };
 FILE * (*rcsopen) (struct buf *, struct stat *, int);
@@ -12370,6 +12381,10 @@ if test "${with_libpam+set}" = set; then
   withval=$with_libpam;
 fi
 
+# Check whether --with-libgcrypt was given.
+if test "${with_libgcrypt+set}" = set; then :
+  withval=$with_libgcrypt;
+fi
 # Check whether --enable-tcp-zebra was given.
 if test "${enable_tcp_zebra+set}" = set; then :
   enableval=$enable_tcp_zebra;
@@ -18052,6 +18067,220 @@ fi
 
 fi
 
+if test "$with_libgcrypt" = "yes"; then
+# Check whether --with-libgcrypt-prefix was given.
+if test "${with_libgcrypt_prefix+set}" = set; then :
+  withval=$with_libgcrypt_prefix; libgcrypt_config_prefix="$withval"
+else
+  libgcrypt_config_prefix=""
+fi
+
+  if test x$libgcrypt_config_prefix != x ; then
+     if test x${LIBGCRYPT_CONFIG+set} != xset ; then
+        LIBGCRYPT_CONFIG=$libgcrypt_config_prefix/bin/libgcrypt-config
+     fi
+  fi
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}libgcrypt-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}libgcrypt-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_LIBGCRYPT_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $LIBGCRYPT_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_LIBGCRYPT_CONFIG="$LIBGCRYPT_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_LIBGCRYPT_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+LIBGCRYPT_CONFIG=$ac_cv_path_LIBGCRYPT_CONFIG
+if test -n "$LIBGCRYPT_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBGCRYPT_CONFIG" >&5
+$as_echo "$LIBGCRYPT_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+fi
+if test -z "$ac_cv_path_LIBGCRYPT_CONFIG"; then
+  ac_pt_LIBGCRYPT_CONFIG=$LIBGCRYPT_CONFIG
+  # Extract the first word of "libgcrypt-config", so it can be a program name with args.
+set dummy libgcrypt-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_LIBGCRYPT_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $ac_pt_LIBGCRYPT_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_ac_pt_LIBGCRYPT_CONFIG="$ac_pt_LIBGCRYPT_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_ac_pt_LIBGCRYPT_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+  ;;
+esac
+fi
+ac_pt_LIBGCRYPT_CONFIG=$ac_cv_path_ac_pt_LIBGCRYPT_CONFIG
+if test -n "$ac_pt_LIBGCRYPT_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_LIBGCRYPT_CONFIG" >&5
+$as_echo "$ac_pt_LIBGCRYPT_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_pt_LIBGCRYPT_CONFIG" = x; then
+    LIBGCRYPT_CONFIG="no"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    LIBGCRYPT_CONFIG=$ac_pt_LIBGCRYPT_CONFIG
+  fi
+else
+  LIBGCRYPT_CONFIG="$ac_cv_path_LIBGCRYPT_CONFIG"
+fi
+  tmp=1.2.0
+  if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then
+     req_libgcrypt_api=`echo "$tmp"     | sed 's/\(.*\):\(.*\)/\1/'`
+     min_libgcrypt_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'`
+  else
+     req_libgcrypt_api=0
+     min_libgcrypt_version="$tmp"
+  fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBGCRYPT - version >= $min_libgcrypt_version" >&5
+$as_echo_n "checking for LIBGCRYPT - version >= $min_libgcrypt_version... " >&6; }
+  ok=no
+  if test "$LIBGCRYPT_CONFIG" != "no" ; then
+    req_major=`echo $min_libgcrypt_version | \
+               sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'`
+    req_minor=`echo $min_libgcrypt_version | \
+               sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'`
+    req_micro=`echo $min_libgcrypt_version | \
+               sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'`
+    libgcrypt_config_version=`$LIBGCRYPT_CONFIG --version`
+    major=`echo $libgcrypt_config_version | \
+               sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\1/'`
+    minor=`echo $libgcrypt_config_version | \
+               sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\2/'`
+    micro=`echo $libgcrypt_config_version | \
+               sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\3/'`
+    if test "$major" -gt "$req_major"; then
+        ok=yes
+    else
+        if test "$major" -eq "$req_major"; then
+            if test "$minor" -gt "$req_minor"; then
+               ok=yes
+            else
+               if test "$minor" -eq "$req_minor"; then
+                   if test "$micro" -ge "$req_micro"; then
+                     ok=yes
+                   fi
+               fi
+            fi
+        fi
+    fi
+  fi
+  if test $ok = yes; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes ($libgcrypt_config_version)" >&5
+$as_echo "yes ($libgcrypt_config_version)" >&6; }
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  fi
+  if test $ok = yes; then
+     # If we have a recent libgcrypt, we should also check that the
+     # API is compatible
+     if test "$req_libgcrypt_api" -gt 0 ; then
+        tmp=`$LIBGCRYPT_CONFIG --api-version 2>/dev/null || echo 0`
+        if test "$tmp" -gt 0 ; then
+           { $as_echo "$as_me:${as_lineno-$LINENO}: checking LIBGCRYPT API version" >&5
+$as_echo_n "checking LIBGCRYPT API version... " >&6; }
+           if test "$req_libgcrypt_api" -eq "$tmp" ; then
+             { $as_echo "$as_me:${as_lineno-$LINENO}: result: okay" >&5
+$as_echo "okay" >&6; }
+           else
+             ok=no
+             { $as_echo "$as_me:${as_lineno-$LINENO}: result: does not match. want=$req_libgcrypt_api got=$tmp" >&5
+$as_echo "does not match. want=$req_libgcrypt_api got=$tmp" >&6; }
+           fi
+        fi
+     fi
+  fi
+  if test $ok = yes; then
+    LIBGCRYPT_CFLAGS=`$LIBGCRYPT_CONFIG --cflags`
+    LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG --libs`
+    :
+    if test x"$host" != x ; then
+      libgcrypt_config_host=`$LIBGCRYPT_CONFIG --host 2>/dev/null || echo none`
+      if test x"$libgcrypt_config_host" != xnone ; then
+        if test x"$libgcrypt_config_host" != x"$host" ; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING:
+***
+*** The config script $LIBGCRYPT_CONFIG was
+*** built for $libgcrypt_config_host and thus may not match the
+*** used host $host.
+*** You may want to use the configure option --with-libgcrypt-prefix
+*** to specify a matching config script.
+***" >&5
+$as_echo "$as_me: WARNING:
+***
+*** The config script $LIBGCRYPT_CONFIG was
+*** built for $libgcrypt_config_host and thus may not match the
+*** used host $host.
+*** You may want to use the configure option --with-libgcrypt-prefix
+*** to specify a matching config script.
+***" >&2;}
+        fi
+      fi
+    fi
+  else
+    LIBGCRYPT_CFLAGS=""
+    LIBGCRYPT_LIBS=""
+    as_fn_error $? "'NOT FOUND: libgcrypt'" "$LINENO" 5
+  fi
+	LIBS="${LIBS} ${LIBGCRYPT_LIBS}"
+	CFLAGS="${CFLAGS} ${LIBGCRYPT_CFLAGS}"
+
+$as_echo "#define HAVE_LIBGCRYPT /**/" >>confdefs.h
+
+
+fi
 ac_fn_c_check_type "$LINENO" "struct sockaddr" "ac_cv_type_struct_sockaddr" "#ifdef SUNOS_5
 #define _XPG4_2
 #define __EXTENSIONS__
@@ -23434,7 +23663,8 @@ compiler                : ${CC}
 compiler flags          : ${CFLAGS}
 make                    : ${MAKE-make}
 includes                : ${INCLUDES} ${SNMP_INCLUDES}
-linker flags            : ${LDFLAGS} ${LIBS} ${LIBCAP} ${LIBREADLINE} ${LIBM}
+linker flags            : ${LDFLAGS} ${LIBS}
+linker conditional libs : ${LIBCAP} ${LIBREADLINE} ${LIBM}
 state file directory    : ${quagga_statedir}
 config file directory   : `eval echo \`echo ${sysconfdir}\``
 example directory       : `eval echo \`echo ${exampledir}\``
diff -upwbNr quagga-0.99.21/configure.ac quagga-rfc6506/configure.ac
--- quagga-0.99.21/configure.ac	2012-05-02 01:12:00.000000000 +0530
+++ quagga-rfc6506/configure.ac	2013-07-11 14:41:22.000000000 +0530
@@ -227,6 +227,8 @@ AC_ARG_ENABLE(snmp,
 [  --enable-snmp           enable SNMP support])
 AC_ARG_WITH(libpam,
 [  --with-libpam           use libpam for PAM support in vtysh])
+AC_ARG_WITH(libgcrypt,
+[  --with-libgcrypt        use gcrypt library for crypto functions])
 AC_ARG_ENABLE(tcp-zebra,
 [  --enable-tcp-zebra      enable TCP/IP socket connection between zebra and protocol daemon])
 AC_ARG_ENABLE(opaque-lsa,
@@ -1382,6 +1384,20 @@ if test "${enable_snmp}" = "yes"; then
     AC_SUBST(SNMP_INCLUDES)
 fi
 
+dnl -----------------------------------------------------------------------
+dnl A "HAVE_LIBGCRYPT" macro will be defined, if --with-libgcrypt configure
+dnl option is given and the library is available (along with Quagga functions
+dnl directly dependent on libgcrypt). Each protocol process using libgcrypt
+dnl must call hash_library_init() once before calling any other libgcrypt
+dnl functions.
+dnl -----------------------------------------------------------------------
+if test "$with_libgcrypt" = "yes"; then
+	AM_PATH_LIBGCRYPT([1.2.0], [], AC_MSG_ERROR('NOT FOUND: libgcrypt'))
+	LIBS="${LIBS} ${LIBGCRYPT_LIBS}"
+	CFLAGS="${CFLAGS} ${LIBGCRYPT_CFLAGS}"
+	AC_DEFINE(HAVE_LIBGCRYPT,,[libgcrypt])
+	AC_SUBST(HAVE_LIBGCRYPT)
+fi
 dnl ---------------------------
 dnl sockaddr and netinet checks
 dnl ---------------------------
@@ -1626,7 +1642,8 @@ compiler                : ${CC}
 compiler flags          : ${CFLAGS}
 make                    : ${MAKE-make}
 includes                : ${INCLUDES} ${SNMP_INCLUDES}
-linker flags            : ${LDFLAGS} ${LIBS} ${LIBCAP} ${LIBREADLINE} ${LIBM}
+linker flags            : ${LDFLAGS} ${LIBS}
+linker conditional libs : ${LIBCAP} ${LIBREADLINE} ${LIBM}
 state file directory    : ${quagga_statedir}
 config file directory   : `eval echo \`echo ${sysconfdir}\``
 example directory       : `eval echo \`echo ${exampledir}\``
diff -upwbNr quagga-0.99.21/lib/cryptohash.c quagga-rfc6506/lib/cryptohash.c
--- quagga-0.99.21/lib/cryptohash.c	1970-01-01 05:30:00.000000000 +0530
+++ quagga-rfc6506/lib/cryptohash.c	2013-07-10 10:11:00.000000000 +0530
@@ -0,0 +1,272 @@
+/*
+ * This file, a part of Quagga, implements an interface to crypto hashes.
+ *
+ *
+ * Quagga is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * Quagga is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Quagga; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+#include "cryptohash.h"
+#include "md5.h"
+#include "command.h"
+
+#ifdef HAVE_LIBGCRYPT
+#define GCRYPT_NO_DEPRECATED
+#include <gcrypt.h>
+#endif /* HAVE_LIBGCRYPT */
+
+const struct message hash_algo_str[] =
+{
+  { HASH_KEYED_MD5,       "Keyed-MD5"        },
+  { HASH_HMAC_SHA1,       "HMAC-SHA-1"       },
+  { HASH_HMAC_SHA256,     "HMAC-SHA-256"     },
+  { HASH_HMAC_SHA384,     "HMAC-SHA-384"     },
+  { HASH_HMAC_SHA512,     "HMAC-SHA-512"     },
+  { HASH_HMAC_RMD160,     "HMAC-RIPEMD-160"  },
+  { HASH_HMAC_WHIRLPOOL,  "HMAC-Whirlpool"   },
+};
+const size_t hash_algo_str_max = sizeof (hash_algo_str) / sizeof (struct message);
+
+/* hash_algo_byname() assumes this array to be exactly HASH_ALGO_MAX items big */
+const struct message hash_algo_cli_str[] =
+{
+  { HASH_KEYED_MD5,       "md5"              },
+  { HASH_HMAC_SHA1,       "sha1"             },
+  { HASH_HMAC_SHA256,     "sha256"           },
+  { HASH_HMAC_SHA384,     "sha384"           },
+  { HASH_HMAC_SHA512,     "sha512"           },
+  { HASH_HMAC_RMD160,     "rmd160"           },
+  { HASH_HMAC_WHIRLPOOL,  "whirlpool"        },
+};
+const size_t hash_algo_cli_str_max = sizeof (hash_algo_cli_str) / sizeof (struct message);
+
+/* hash digest size map */
+const u_int8_t hash_digest_length[] =
+{
+  [HASH_KEYED_MD5]       = HASH_SIZE_MD5,
+  [HASH_HMAC_SHA1]       = HASH_SIZE_SHA1,
+  [HASH_HMAC_SHA256]     = HASH_SIZE_SHA256,
+  [HASH_HMAC_SHA384]     = HASH_SIZE_SHA384,
+  [HASH_HMAC_SHA512]     = HASH_SIZE_SHA512,
+  [HASH_HMAC_RMD160]     = HASH_SIZE_RMD160,
+  [HASH_HMAC_WHIRLPOOL]  = HASH_SIZE_WHIRLPOOL,
+};
+
+/* RFC4822 2.5: Apad is the hexadecimal value 0x878FE1F3 repeated (L/4) times. */
+const u_int8_t hash_apad_sha512[HASH_SIZE_SHA512] =
+{
+  0x87, 0x8f, 0xe1, 0xf3,   0x87, 0x8f, 0xe1, 0xf3,
+  0x87, 0x8f, 0xe1, 0xf3,   0x87, 0x8f, 0xe1, 0xf3,
+  0x87, 0x8f, 0xe1, 0xf3,   0x87, 0x8f, 0xe1, 0xf3,
+  0x87, 0x8f, 0xe1, 0xf3,   0x87, 0x8f, 0xe1, 0xf3,
+  0x87, 0x8f, 0xe1, 0xf3,   0x87, 0x8f, 0xe1, 0xf3,
+  0x87, 0x8f, 0xe1, 0xf3,   0x87, 0x8f, 0xe1, 0xf3,
+  0x87, 0x8f, 0xe1, 0xf3,   0x87, 0x8f, 0xe1, 0xf3,
+  0x87, 0x8f, 0xe1, 0xf3,   0x87, 0x8f, 0xe1, 0xf3,
+};
+
+#ifdef HAVE_LIBGCRYPT
+/* ripd to gcrypto hash algorithm code map */
+static const int hash_gcrypt_algo_map[] =
+{
+  [HASH_HMAC_SHA1]       = GCRY_MD_SHA1,
+  [HASH_HMAC_SHA256]     = GCRY_MD_SHA256,
+  [HASH_HMAC_SHA384]     = GCRY_MD_SHA384,
+  [HASH_HMAC_SHA512]     = GCRY_MD_SHA512,
+  [HASH_HMAC_RMD160]     = GCRY_MD_RMD160,
+  [HASH_HMAC_WHIRLPOOL]  = GCRY_MD_WHIRLPOOL,
+};
+#endif /* HAVE_LIBGCRYPT */
+
+/* available only in processes with a call to hash_library_init() */
+DEFUN (show_crypto,
+       show_crypto_cmd,
+       "show crypto",
+       SHOW_STR
+       "Crypto module information\n")
+{
+#ifdef HAVE_LIBGCRYPT
+  unsigned i;
+  vty_out (vty, "Compiled with libgcrypt version %s%s", GCRYPT_VERSION, VTY_NEWLINE);
+  vty_out (vty, "Running with libgcrypt version %s%s", gcry_check_version (NULL), VTY_NEWLINE);
+  for (i = 0; i < sizeof (hash_gcrypt_algo_map) / sizeof (hash_gcrypt_algo_map[0]); i++)
+    if (hash_gcrypt_algo_map[i])
+      vty_out (vty, "%-17s: %s%s", LOOKUP (hash_algo_str, i),
+               hash_algo_enabled (i) ? "enabled" : "disabled", VTY_NEWLINE);
+#else
+  vty_out (vty, "Compiled without libgcrypt%s", VTY_NEWLINE);
+#endif /* HAVE_LIBGCRYPT */
+  return CMD_SUCCESS;
+}
+
+extern unsigned
+hash_library_init (void)
+{
+#ifdef HAVE_LIBGCRYPT
+  if (! gcry_check_version (GCRYPT_VERSION))
+  {
+    zlog_err ("libgcrypt initialization failed");
+    return 1;
+  }
+  gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+  install_element (VIEW_NODE, &show_crypto_cmd);
+  install_element (ENABLE_NODE, &show_crypto_cmd);
+#endif /* HAVE_LIBGCRYPT */
+  return 0;
+}
+
+/* Map a string name of a listed hash algorithm into Quagga internal code. */
+unsigned
+hash_algo_byname (const char *algo)
+{
+  unsigned i;
+
+  for (i = 0; i < HASH_ALGO_MAX; i++)
+    if (! strcmp (algo, hash_algo_cli_str[i].str))
+      return hash_algo_cli_str[i].key;
+  return 0;
+}
+
+/* Test whether a hash algorithm with the given Quagga code is available in the
+ * current runtime. Using this function requires neither libgcrypt presence nor
+ * knowing libgcrypt internal code for the hash algorithm. */
+unsigned char
+hash_algo_enabled (const unsigned hash_algo)
+{
+  switch (hash_algo)
+  {
+  case HASH_KEYED_MD5:
+    return 1;
+#ifdef HAVE_LIBGCRYPT
+  case HASH_HMAC_SHA1:
+  case HASH_HMAC_SHA256:
+  case HASH_HMAC_SHA384:
+  case HASH_HMAC_SHA512:
+  case HASH_HMAC_RMD160:
+  case HASH_HMAC_WHIRLPOOL:
+    return 0 == gcry_md_test_algo (hash_gcrypt_algo_map[hash_algo]);
+#endif /* HAVE_LIBGCRYPT */
+  default:
+    return 0;
+  }
+}
+
+/* Process input data with Keyed-MD5 algorithm and store digest as output. */
+unsigned
+hash_make_keyed_md5
+(
+  const void *input,
+  const size_t inputlen,
+  const void *auth_str,
+  const size_t auth_str_len,
+  void *output
+)
+{
+  char auth_str_padded[HASH_SIZE_MD5] = { 0 };
+  MD5_CTX ctx;
+
+  memcpy (auth_str_padded, auth_str, MIN (HASH_SIZE_MD5, auth_str_len));
+  memset (&ctx, 0, sizeof (ctx));
+  MD5Init (&ctx);
+  MD5Update (&ctx, input, inputlen);
+  MD5Update (&ctx, auth_str_padded, HASH_SIZE_MD5);
+  MD5Final (output, &ctx);
+  return 0;
+}
+
+#ifdef HAVE_LIBGCRYPT
+/* Process input data with a HMAC algorithm using the given hash function and
+ * store digest as output. It is safe for output digest buffer to be within
+ * input buffer. */
+unsigned
+hash_make_hmac
+(
+  const unsigned hash_algo,
+  const void *input,
+  const size_t inputlen,
+  const void *auth_str,
+  const size_t authlen,
+  void *output
+)
+{
+  gcry_md_hd_t ctx;
+
+  if (gcry_md_open (&ctx, hash_gcrypt_algo_map[hash_algo], GCRY_MD_FLAG_HMAC))
+    return 1;
+  /* gcrypt handles preparing the key, Ipad and Opad */
+  if (gcry_md_setkey (ctx, auth_str, authlen))
+  {
+    gcry_md_close (ctx);
+    return 2;
+  }
+  gcry_md_write (ctx, input, inputlen);
+  gcry_md_final (ctx);
+  memcpy (output, gcry_md_read (ctx, 0), hash_digest_length[hash_algo]);
+  gcry_md_close (ctx);
+  return 0;
+}
+
+/* The construct defined in RFC4822 and reused in RFC5709, RFC6506 and probably
+ * other works is similar to HMAC (RFC2104) but is not HMAC, to be precise. The
+ * principal difference is in the key preparation step. The original RFC2104
+ * construct defines Ko to be B octets long and derives Ko from K respectively,
+ * whereas RFC4822 construct defines Ko to be L octets long (L <= B). Since
+ * L < B for most modern hash functions, these two constructs produce different
+ * digests for the same Text and K, when length of K is greater than L but not
+ * greater than B.
+ *
+ * In practice this means, that an implementation of RFC4822 construct (e. g.
+ * ripd) can reuse an existing implementation of HMAC (e. g. libgcrypt) as long
+ * as the authentication key is pre-processed with the function below. At the
+ * same time, this processing must not be performed by an implementation of the
+ * original HMAC construct (e. g. babeld).
+ */
+void
+hash_key_compress_rfc4822
+(
+  const unsigned hash_algo,
+  const void *orig_key_bytes,
+  const size_t orig_key_len,
+  void *compr_key_bytes, /* size must be >= hash_algo digest length */
+  size_t *compr_key_len
+)
+{
+  switch (hash_algo)
+  {
+  case HASH_HMAC_SHA1:
+  case HASH_HMAC_SHA256:
+  case HASH_HMAC_SHA384:
+  case HASH_HMAC_SHA512:
+  case HASH_HMAC_RMD160:
+  case HASH_HMAC_WHIRLPOOL:
+    if (orig_key_len > hash_digest_length[hash_algo] ) /* > L, Ko := H(K) */
+    {
+      gcry_md_hash_buffer (hash_gcrypt_algo_map[hash_algo], compr_key_bytes, orig_key_bytes, orig_key_len);
+      *compr_key_len = hash_digest_length[hash_algo];
+    }
+    else /* <= L */
+    {
+      memset (compr_key_bytes, 0, hash_digest_length[hash_algo]);
+      memcpy (compr_key_bytes, orig_key_bytes, orig_key_len);
+      *compr_key_len = orig_key_len;
+    }
+    break;
+  default:
+    assert (0);
+  }
+}
+#endif /* HAVE_LIBGCRYPT */
diff -upwbNr quagga-0.99.21/lib/cryptohash.h quagga-rfc6506/lib/cryptohash.h
--- quagga-0.99.21/lib/cryptohash.h	1970-01-01 05:30:00.000000000 +0530
+++ quagga-rfc6506/lib/cryptohash.h	2013-07-10 10:14:00.000000000 +0530
@@ -0,0 +1,60 @@
+/*
+ * This file, a part of Quagga, implements an interface to crypto hashes.
+ *
+ *
+ * Quagga is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * Quagga is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Quagga; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef QUAGGA_CRYPTOHASH_H
+#define QUAGGA_CRYPTOHASH_H
+
+#include "log.h"
+
+#define HASH_KEYED_MD5               1
+#define HASH_HMAC_SHA1               2
+#define HASH_HMAC_SHA256             3
+#define HASH_HMAC_SHA384             4
+#define HASH_HMAC_SHA512             5
+#define HASH_HMAC_RMD160             6
+#define HASH_HMAC_WHIRLPOOL          7
+#define HASH_ALGO_MAX                7
+
+#define HASH_SIZE_MD5               16U
+#define HASH_SIZE_SHA1              20U
+#define HASH_SIZE_SHA256            32U
+#define HASH_SIZE_SHA384            48U
+#define HASH_SIZE_SHA512            64U
+#define HASH_SIZE_RMD160            20U
+#define HASH_SIZE_WHIRLPOOL         64U
+#define HASH_SIZE_MAX               64U
+
+extern const struct message hash_algo_str[];
+extern const size_t hash_algo_str_max;
+extern const struct message hash_algo_cli_str[];
+extern const size_t hash_algo_cli_str_max;
+extern const u_int8_t hash_digest_length[];
+extern const u_int8_t hash_apad_sha512[];
+
+extern unsigned hash_library_init (void);
+extern unsigned hash_algo_byname (const char *);
+extern unsigned char hash_algo_enabled (const unsigned);
+extern unsigned hash_make_keyed_md5 (const void *, const size_t, const void *, const size_t, void *);
+#ifdef HAVE_LIBGCRYPT
+extern unsigned hash_make_hmac (const unsigned, const void *, const size_t, const void *, const size_t, void *);
+extern void hash_key_compress_rfc4822 (const unsigned, const void *, const size_t, void *, size_t *);
+#endif /* HAVE_LIBGCRYPT */
+
+#endif /* QUAGGA_CRYPTOHASH_H */
diff -upwbNr quagga-0.99.21/lib/Makefile.am quagga-rfc6506/lib/Makefile.am
--- quagga-0.99.21/lib/Makefile.am	2012-05-02 01:10:12.000000000 +0530
+++ quagga-rfc6506/lib/Makefile.am	2013-07-10 10:14:00.000000000 +0530
@@ -12,7 +12,7 @@ libzebra_la_SOURCES = \
 	sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \
 	filter.c routemap.c distribute.c stream.c str.c log.c plist.c \
 	zclient.c sockopt.c smux.c md5.c if_rmap.c keychain.c privs.c \
-	sigevent.c pqueue.c jhash.c memtypes.c workqueue.c
+	sigevent.c pqueue.c jhash.c memtypes.c workqueue.c cryptohash.c
 
 BUILT_SOURCES = memtypes.h route_types.h
 
@@ -27,7 +27,7 @@ pkginclude_HEADERS = \
 	str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \
 	plist.h zclient.h sockopt.h smux.h md5.h if_rmap.h keychain.h \
 	privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \
-	workqueue.h route_types.h
+	workqueue.h route_types.h cryptohash.h
 
 EXTRA_DIST = regex.c regex-gnu.h memtypes.awk route_types.pl route_types.txt
 
diff -upwbNr quagga-0.99.21/lib/memtypes.c quagga-rfc6506/lib/memtypes.c
--- quagga-0.99.21/lib/memtypes.c	2012-05-01 21:40:26.000000000 +0530
+++ quagga-rfc6506/lib/memtypes.c	2013-07-10 10:14:00.000000000 +0530
@@ -216,6 +216,7 @@ struct memory_list memory_list_ospf6[] =
 {
   { MTYPE_OSPF6_TOP,          "OSPF6 top"			},
   { MTYPE_OSPF6_AREA,         "OSPF6 area"			},
+  { MTYPE_OSPF6_CRYPT_KEY,    "OSPF6 crypt key"		},
   { MTYPE_OSPF6_IF,           "OSPF6 interface"		},
   { MTYPE_OSPF6_NEIGHBOR,     "OSPF6 neighbor"			},
   { MTYPE_OSPF6_ROUTE,        "OSPF6 route"			},

diff -upwbNr quagga-0.99.21/ospf6d/ospf6_interface.c quagga-rfc6506/ospf6d/ospf6_interface.c
--- quagga-0.99.21/ospf6d/ospf6_interface.c	2012-03-24 01:13:18.000000000 +0530
+++ quagga-rfc6506/ospf6d/ospf6_interface.c	2013-10-25 15:01:24.000000000 +0530
@@ -29,6 +29,19 @@
 #include "prefix.h"
 #include "plist.h"
 
+#include "sockunion.h"
+#include "network.h"
+#include "table.h"
+#include "stream.h"
+#include "zclient.h"
+#include "filter.h"
+#include "sockopt.h"
+#include "privs.h"
+#include "cryptohash.h"
+#include "keychain.h"
+
+#include "zebra/connected.h"
+
 #include "ospf6_lsa.h"
 #include "ospf6_lsdb.h"
 #include "ospf6_network.h"
@@ -41,6 +54,7 @@
 #include "ospf6_intra.h"
 #include "ospf6_spf.h"
 #include "ospf6d.h"
+#include "memtypes.h"
 
 unsigned char conf_debug_ospf6_interface = 0;
 
@@ -141,6 +155,14 @@ ospf6_interface_create (struct interface
   oi->route_connected = OSPF6_ROUTE_TABLE_CREATE (INTERFACE, CONNECTED_ROUTES);
   oi->route_connected->scope = oi;
 
+  if (oi->key_chain)
+    XFREE (MTYPE_OSPF6_CRYPT_KEY, oi->key_chain);
+
+  oi->low_order_seqnum = time (NULL);
+  oi->high_order_seqnum = 0;
+  oi->auth_type = 0;
+  oi->hash_algo = 0;
+
   /* link both */
   oi->interface = ifp;
   ifp->info = oi;
@@ -840,6 +862,7 @@ ospf6_interface_show (struct vty *vty, s
   return 0;
 }
 
+
 /* show interface */
 DEFUN (show_ipv6_ospf6_interface,
        show_ipv6_ospf6_interface_ifname_cmd,
@@ -1504,10 +1527,156 @@ DEFUN (no_ipv6_ospf6_advertise_prefix_li
   return CMD_SUCCESS;
 }
 
+DEFUN (ipv6_ospf6_sha_authentication_mode,
+       ipv6_ospf6_sha_authentication_mode_cmd,
+       "ipv6 ospf6 authentication mode (sha1|sha256|sha384|sha512|default)",
+       "IPv6 Information\n"
+       "OSPF6 interface commands\n"
+       "Authentication mode\n"
+       "HMAC-SHA-1 authentication\n"
+       "HMAC-SHA-256 authentication\n"
+       "HMAC-SHA-384 authentication\n"
+       "HMAC-SHA-512 authentication\n"
+       "Enable SHA algorithm for authentication\n"
+       )
+{
+  struct ospf6_interface *oi;
+  struct interface *ifp;
+  unsigned hash_algo;
+  struct listnode *node, *nnode;	
+  struct list *auth_crypt;		
+  u_char key_id;
+
+  ifp = (struct interface *)vty->index;
+  assert (ifp);
+
+  oi = (struct ospf6_interface *)ifp->info;
+  if (oi == NULL)
+    oi = ospf6_interface_create (ifp);
+  assert (oi);
+
+  /* As per RFC-6506, default sha algorithm is sha-256 */
+  if(strcmp(argv[0],"default")==0)
+    hash_algo = hash_algo_byname ("sha256");
+  else
+    hash_algo = hash_algo_byname (argv[0]);
+  
+  if (! hash_algo_enabled (hash_algo))
+  {
+    vty_out (vty, "Algorithm '%s' is not enabled in this build%s", argv[0], VTY_NEWLINE);
+    return CMD_ERR_NO_MATCH;
+  }
+  
+  
+  oi->auth_type = OSPF6_AUTH_CRYPTOGRAPHIC;
+  oi->hash_algo = hash_algo;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_ospf6_sha_authentication_mode,
+       no_ipv6_ospf6_sha_authentication_mode_cmd,
+       "no ipv6 ospf6 authentication mode",
+       NO_STR
+       "IPv6 Information\n"
+       "OSPF6 interface commands\n"
+       "Disable SHA algorithm for authentication\n"
+       )
+{
+  struct ospf6_interface *oi;
+  struct interface *ifp;
+
+  ifp = (struct interface *) vty->index;
+  assert (ifp);
+
+  oi = (struct ospf6_interface *) ifp->info;
+  if (oi == NULL)
+  oi = ospf6_interface_create (ifp);
+  assert (oi);
+
+  oi->auth_type = OSPF6_AUTH_NULL ;
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ipv6_ospf6_sha_authentication_mode,
+       no_ipv6_ospf6_sha_authentication_mode_type_cmd,
+       "no ipv6 ospf6 authentication mode (sha1|sha256|sha384|sha512)",
+       NO_STR
+       "IPv6 Information\n"
+       "OSPF6 interface commands\n"
+       "Disable SHA algorithm for authentication\n"
+       "HMAC-SHA-1 authentication\n"
+       "HMAC-SHA-256 authentication\n"
+       "HMAC-SHA-384 authentication\n"
+       "HMAC-SHA-512 authentication\n")
+
+DEFUN (ipv6_ospf6_authentication_key_chain,
+       ipv6_ospf6_authentication_key_chain_cmd,
+       "ipv6 ospf6 authentication key-chain LINE",
+       "IPv6 Information\n"
+       "Authentication control\n"
+       "Authentication key-chain\n"
+       "name of key-chain\n")
+{
+  struct interface *ifp;
+  struct ospf6_interface *oi;
+
+  ifp = (struct interface *) vty->index;
+  assert (ifp);
+
+  oi = (struct ospf6_interface *) ifp->info;
+  
+  if (oi == NULL)
+  oi = ospf6_interface_create (ifp);
+  assert (oi);
+
+  if (keychain_lookup (argv[0]) == NULL)
+  {
+       vty_out (vty, "Keychain '%s' is not configured%s", argv[0], VTY_NEWLINE);
+       return 0;
+  }
+
+  if (oi->key_chain)
+    XFREE (MTYPE_OSPF6_CRYPT_KEY, oi->key_chain);
+
+  oi->key_chain = XSTRDUP (MTYPE_OSPF6_CRYPT_KEY, argv[0]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_ospf6_authentication_key_chain,
+       no_ipv6_ospf6_authentication_key_chain_cmd,
+       "no ipv6 ospf6 authentication key-chain",
+       NO_STR
+       "IPv6 Information\n"
+       "Authentication control\n"
+       "Authentication key-chain\n")
+{
+  struct interface *ifp;
+  struct ospf6_interface *oi;
+
+  ifp = (struct interface *) vty->index;
+  oi = ifp->info;
+
+  if (oi->key_chain)
+    XFREE (MTYPE_OSPF6_CRYPT_KEY, oi->key_chain);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ipv6_ospf6_authentication_key_chain,
+       no_ipv6_ospf6_authentication_key_chain2_cmd,
+       "no ipv6 ospf6 authentication key-chain LINE",
+       NO_STR
+       "IPv6 Information\n"
+       "Authentication control\n"
+       "Authentication key-chain\n"
+       "name of key-chain\n")
+
 static int
 config_write_ospf6_interface (struct vty *vty)
 {
   struct listnode *i;
+  struct keychain *keychain;
   struct ospf6_interface *oi;
   struct interface *ifp;
 
@@ -1563,6 +1732,29 @@ config_write_ospf6_interface (struct vty
       if (oi->mtu_ignore)
         vty_out (vty, " ipv6 ospf6 mtu-ignore%s", VNL);
 
+      /* OSPFv3 authentication. */
+      if (oi->auth_type == OSPF6_AUTH_NULL)
+        vty_out (vty, " ipv6 ospf6 authentication mode NULL%s", VTY_NEWLINE);
+
+      if (oi->auth_type == OSPF6_AUTH_CRYPTOGRAPHIC)
+        switch (oi->hash_algo)
+        {
+        case HASH_HMAC_SHA1:
+        case HASH_HMAC_SHA256:
+        case HASH_HMAC_SHA384:
+        case HASH_HMAC_SHA512:
+          vty_out (vty, " ipv6 ospf6 authentication mode %s%s",
+                   LOOKUP (hash_algo_cli_str, oi->hash_algo), VTY_NEWLINE);
+          break;
+        default:
+          assert (0);
+        }
+
+      if (oi->key_chain)
+        vty_out (vty, " ipv6 ospf6 authentication key-chain %s%s",
+                 oi->key_chain, VTY_NEWLINE);
+
+
       vty_out (vty, "!%s", VNL);
     }
   return 0;
@@ -1620,6 +1812,14 @@ ospf6_interface_init (void)
 
   install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_prefix_list_cmd);
   install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_prefix_list_cmd);
+
+  install_element (INTERFACE_NODE, &ipv6_ospf6_authentication_key_chain_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_ospf6_authentication_key_chain_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_ospf6_authentication_key_chain2_cmd);
+  
+  install_element (INTERFACE_NODE, &ipv6_ospf6_sha_authentication_mode_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_ospf6_sha_authentication_mode_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_ospf6_sha_authentication_mode_type_cmd);
 }
 
 DEFUN (debug_ospf6_interface,
diff -upwbNr quagga-0.99.21/ospf6d/ospf6_interface.h quagga-rfc6506/ospf6d/ospf6_interface.h
--- quagga-0.99.21/ospf6d/ospf6_interface.h	2012-03-24 01:13:18.000000000 +0530
+++ quagga-rfc6506/ospf6d/ospf6_interface.h	2013-10-09 13:53:33.000000000 +0530
@@ -33,6 +33,8 @@ extern unsigned char conf_debug_ospf6_in
 #define IS_OSPF6_DEBUG_INTERFACE \
   (conf_debug_ospf6_interface)
 
+#define OSPF6_AUTH_DATA_SIZE 		64U
+
 /* Interface structure */
 struct ospf6_interface
 {
@@ -105,6 +107,14 @@ struct ospf6_interface
 
   /* prefix-list name to filter connected prefix */
   char *plist_name;
+
+  u_int32_t high_order_seqnum;	    /* higher order Cryptographic Sequence Number */
+  u_int32_t low_order_seqnum;	    /* lower order Cryptographic Sequence Number */
+  int hash_algo;                    /* hash algorithm type */
+  u_int8_t auth_type;               /* OSPFv3 authentication type for interface */ 
+  char *auth_str;		    /* OSPFv3 authentication string */
+  char *key_chain;                  /* OSPFv3 authentication key chain */
+
 };
 
 /* interface state */
diff -upwbNr quagga-0.99.21/ospf6d/ospf6_main.c quagga-rfc6506/ospf6d/ospf6_main.c
--- quagga-0.99.21/ospf6d/ospf6_main.c	2012-05-02 01:10:12.000000000 +0530
+++ quagga-rfc6506/ospf6d/ospf6_main.c	2013-10-07 12:58:19.000000000 +0530
@@ -35,6 +35,8 @@
 #include "privs.h"
 #include "sigevent.h"
 #include "zclient.h"
+#include "keychain.h"
+#include "cryptohash.h"
 
 #include "ospf6d.h"
 #include "ospf6_top.h"
@@ -313,6 +315,7 @@ main (int argc, char *argv[], char *envp
   vty_init (master);
   memory_init ();
   if_init ();
+  keychain_init();
   access_list_init ();
   prefix_list_init ();
 
diff -upwbNr quagga-0.99.21/ospf6d/ospf6_message.c quagga-rfc6506/ospf6d/ospf6_message.c
--- quagga-0.99.21/ospf6d/ospf6_message.c	2012-04-17 19:26:26.000000000 +0530
+++ quagga-rfc6506/ospf6d/ospf6_message.c	2013-10-25 15:38:04.000000000 +0530
@@ -27,6 +27,8 @@
 #include "command.h"
 #include "thread.h"
 #include "linklist.h"
+#include "cryptohash.h"
+#include "keychain.h"
 
 #include "ospf6_proto.h"
 #include "ospf6_lsa.h"
@@ -49,6 +51,10 @@
 
 #include <netinet/ip6.h>
 
+/*Initialization of CPID (Cryptographic Protocol ID)*/
+static const uint16_t CPID =1;
+
+
 unsigned char conf_debug_ospf6_message[6] = {0x03, 0, 0, 0, 0, 0};
 static const struct message ospf6_message_type_str [] =
 {
@@ -58,6 +64,18 @@ static const struct message ospf6_messag
   { OSPF6_MESSAGE_TYPE_LSUPDATE, "LSUpdate" },
   { OSPF6_MESSAGE_TYPE_LSACK,    "LSAck"    },
 };
+
+/* Authentication Types */
+static
+const struct message ospf6_auth_type_string[] =
+{
+  { OSPF6_AUTH_NULL,          "Null"          },
+  { OSPF6_AUTH_CRYPTOGRAPHIC, "Cryptographic" },
+};
+
+static const size_t ospf6_auth_type_string_max =
+  sizeof (ospf6_auth_type_string) / sizeof (ospf6_auth_type_string[0]);
+
 static const size_t ospf6_message_type_str_max =
   sizeof (ospf6_message_type_str) / sizeof (ospf6_message_type_str[0]);
 
@@ -104,11 +122,22 @@ ospf6_header_print (struct ospf6_header
              area_id, ntohs (oh->checksum), oh->instance_id);
 }
 
+void ospf6_print_auth_details(struct ospfv3_crypt *ospf6_at)
+{
+  zlog_debug ("    Auth Type : SHA Cryptographic Authentication");
+  zlog_debug ("    Key ID : %d", ospf6_at->sa_id);
+  zlog_debug ("    Auth Data Len :  %d", ospf6_at->auth_data_length);
+  zlog_debug ("    Higher Sequence number : %ld",
+              (u_long)ntohl (ospf6_at->high_order_seqnum));
+  zlog_debug ("    Lower Sequence number : %ld",
+              (u_long)ntohl (ospf6_at->low_order_seqnum));
+}
+
 void
-ospf6_hello_print (struct ospf6_header *oh)
+ospf6_hello_print (struct ospf6_header *oh, struct ospfv3_crypt *ospf6_at)
 {
   struct ospf6_hello *hello;
-  char options[16];
+  char options[36];
   char drouter[16], bdrouter[16], neighbor[16];
   char *p;
 
@@ -122,6 +151,19 @@ ospf6_hello_print (struct ospf6_header *
   inet_ntop (AF_INET, &hello->bdrouter, bdrouter, sizeof (bdrouter));
   ospf6_options_printbuf (hello->options, options, sizeof (options));
 
+  switch (ospf6_at->auth_type)
+  {
+    case OSPF6_AUTH_NULL:
+         zlog_debug ("    Auth Type : Null Authentication");
+         break;
+    case OSPF6_AUTH_CRYPTOGRAPHIC:
+         ospf6_print_auth_details(ospf6_at);
+         break;
+    default:
+         zlog_debug ("*   This is not supported authentication type");
+         break;
+  }
+
   zlog_debug ("    I/F-Id:%ld Priority:%d Option:%s",
              (u_long) ntohl (hello->interface_id), hello->priority, options);
   zlog_debug ("    HelloInterval:%hu DeadInterval:%hu",
@@ -135,15 +177,14 @@ ospf6_hello_print (struct ospf6_header *
       inet_ntop (AF_INET, (void *) p, neighbor, sizeof (neighbor));
       zlog_debug ("    Neighbor: %s", neighbor);
     }
-
   assert (p == OSPF6_MESSAGE_END (oh));
 }
 
 void
-ospf6_dbdesc_print (struct ospf6_header *oh)
+ospf6_dbdesc_print (struct ospf6_header *oh, struct ospfv3_crypt *ospf6_at)
 {
   struct ospf6_dbdesc *dbdesc;
-  char options[16];
+  char options[36];
   char *p;
 
   ospf6_header_print (oh);
@@ -154,6 +195,19 @@ ospf6_dbdesc_print (struct ospf6_header
 
   ospf6_options_printbuf (dbdesc->options, options, sizeof (options));
 
+  switch (ospf6_at->auth_type)
+  {
+    case OSPF6_AUTH_NULL:
+         zlog_debug ("    Auth Type : Null Authentication");
+         break;
+    case OSPF6_AUTH_CRYPTOGRAPHIC:
+         ospf6_print_auth_details(ospf6_at);
+         break;
+    default:
+         zlog_debug ("*   This is not supported authentication type");
+         break;
+  }
+
   zlog_debug ("    MBZ: %#x Option: %s IfMTU: %hu",
              dbdesc->reserved1, options, ntohs (dbdesc->ifmtu));
   zlog_debug ("    MBZ: %#x Bits: %s%s%s SeqNum: %#lx",
@@ -247,10 +301,13 @@ ospf6_hello_recv (struct in6_addr *src,
   int twoway = 0;
   int neighborchange = 0;
   int backupseen = 0;
+  struct ospfv3_crypt *ospf6_at ;
 
   hello = (struct ospf6_hello *)
     ((caddr_t) oh + sizeof (struct ospf6_header));
 
+  ospf6_at = (struct ospfv3_crypt *)((caddr_t) oh + ntohs (oh->length));
+
   /* HelloInterval check */
   if (ntohs (hello->hello_interval) != oi->hello_interval)
     {
@@ -280,7 +337,7 @@ ospf6_hello_recv (struct in6_addr *src,
   on = ospf6_neighbor_lookup (oh->router_id, oi);
   if (on == NULL)
     {
-      on = ospf6_neighbor_create (oh->router_id, oi);
+      on = ospf6_neighbor_create (oh->router_id, oi , ospf6_at); 
       on->prev_drouter = on->drouter = hello->drouter;
       on->prev_bdrouter = on->bdrouter = hello->bdrouter;
       on->priority = hello->priority;
@@ -1163,12 +1220,31 @@ ospf6_lsaseq_examin
   return MSG_OK;
 }
 
+/* OSPF6 authentication type & AT Bit checking function */
+static int
+ospf6_auth_type (struct ospf6_interface *oi)
+{
+  int auth_type = OSPF6_AUTH_NULL;
+  if(oi->auth_type)   
+    auth_type =  OSPF6_AUTH_CRYPTOGRAPHIC;
+   
+  /* Handle case where MD5 key list is not configured aka Cisco */
+  if (auth_type == OSPF6_AUTH_CRYPTOGRAPHIC &&
+      oi->key_chain == NULL)
+    return OSPF6_AUTH_NULL;
+  
+  return auth_type;
+   
+}
+
 /* Verify a complete OSPF packet for proper sizing/alignment. */
 static unsigned
-ospf6_packet_examin (struct ospf6_header *oh, const unsigned bytesonwire)
+ospf6_packet_examin (struct ospf6_interface *oi, struct ospf6_header *oh, const unsigned bytesonwire)   
 {
   struct ospf6_lsupdate *lsupd;
   unsigned test;
+  u_int16_t bytesdeclared;
+  struct ospfv3_crypt *ospf6_at;
 
   /* length, 1st approximation */
   if (bytesonwire < OSPF6_HEADER_SIZE)
@@ -1178,13 +1254,29 @@ ospf6_packet_examin (struct ospf6_header
     return MSG_NG;
   }
   /* Now it is safe to access header fields. */
-  if (bytesonwire != ntohs (oh->length))
+  bytesdeclared =  ntohs (oh->length);
+  ospf6_at = (struct ospfv3_crypt *)((caddr_t) oh + ntohs (oh->length));
+  if (ospf6_at->auth_type == OSPF6_AUTH_CRYPTOGRAPHIC) //when authentication is cryptographic
+  {
+    if (bytesonwire > ntohs (oh->length) + AUTH_TRAILER_HEADER + OSPF6_AUTH_DATA_SIZE)
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+        zlog_debug ("%s: packet length error (%u real, %u declared)",
+                    __func__, bytesonwire, ntohs (oh->length) + AUTH_TRAILER_HEADER + OSPF6_AUTH_DATA_SIZE);
+      return MSG_NG;
+    }
+  }
+  else //when authentication is NULL 
+  {
+    if (bytesonwire > ntohs (oh->length))
   {
     if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
       zlog_debug ("%s: packet length error (%u real, %u declared)",
                   __func__, bytesonwire, ntohs (oh->length));
     return MSG_NG;
   }
+  }  
+
   /* version check */
   if (oh->version != OSPFV3_VERSION)
   {
@@ -1192,17 +1284,19 @@ ospf6_packet_examin (struct ospf6_header
       zlog_debug ("%s: invalid (%u) protocol version", __func__, oh->version);
     return MSG_NG;
   }
-  /* length, 2nd approximation */
+     
+  /* Length, 2nd approximation. The type-specific constraint is checked
+     against declared length, not amount of bytes on wire. As done in ospfv2 */
   if
   (
     oh->type < OSPF6_MESSAGE_TYPE_ALL &&
     ospf6_packet_minlen[oh->type] &&
-    bytesonwire < OSPF6_HEADER_SIZE + ospf6_packet_minlen[oh->type]
+    bytesdeclared < OSPF6_HEADER_SIZE + ospf6_packet_minlen[oh->type]
   )
   {
     if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
       zlog_debug ("%s: undersized (%u B) %s packet", __func__,
-                  bytesonwire, LOOKUP (ospf6_message_type_str, oh->type));
+                  bytesdeclared, LOOKUP (ospf6_message_type_str, oh->type));
     return MSG_NG;
   }
   /* type-specific deeper validation */
@@ -1211,26 +1305,28 @@ ospf6_packet_examin (struct ospf6_header
   case OSPF6_MESSAGE_TYPE_HELLO:
     /* RFC5340 A.3.2, packet header + OSPF6_HELLO_MIN_SIZE bytes followed
        by N>=0 router-IDs. */
-    if (0 == (bytesonwire - OSPF6_HEADER_SIZE - OSPF6_HELLO_MIN_SIZE) % 4)
+      if (0 == (bytesdeclared - OSPF6_HEADER_SIZE - OSPF6_HELLO_MIN_SIZE ) % 4)
       return MSG_OK;
+
     if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
       zlog_debug ("%s: alignment error in %s packet",
                   __func__, LOOKUP (ospf6_message_type_str, oh->type));
     return MSG_NG;
+
   case OSPF6_MESSAGE_TYPE_DBDESC:
     /* RFC5340 A.3.3, packet header + OSPF6_DB_DESC_MIN_SIZE bytes followed
        by N>=0 header-only LSAs. */
     test = ospf6_lsaseq_examin
     (
       (struct ospf6_lsa_header *) ((caddr_t) oh + OSPF6_HEADER_SIZE + OSPF6_DB_DESC_MIN_SIZE),
-      bytesonwire - OSPF6_HEADER_SIZE - OSPF6_DB_DESC_MIN_SIZE,
+      bytesdeclared - OSPF6_HEADER_SIZE - OSPF6_DB_DESC_MIN_SIZE,
       1,
       0
     );
     break;
   case OSPF6_MESSAGE_TYPE_LSREQ:
     /* RFC5340 A.3.4, packet header + N>=0 LS description blocks. */
-    if (0 == (bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_REQ_MIN_SIZE) % OSPF6_LSREQ_LSDESC_FIX_SIZE)
+    if (0 == (bytesdeclared - OSPF6_HEADER_SIZE - OSPF6_LS_REQ_MIN_SIZE) % OSPF6_LSREQ_LSDESC_FIX_SIZE)
       return MSG_OK;
     if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
       zlog_debug ("%s: alignment error in %s packet",
@@ -1243,7 +1339,7 @@ ospf6_packet_examin (struct ospf6_header
     test = ospf6_lsaseq_examin
     (
       (struct ospf6_lsa_header *) ((caddr_t) lsupd + OSPF6_LS_UPD_MIN_SIZE),
-      bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_UPD_MIN_SIZE,
+      bytesdeclared - OSPF6_HEADER_SIZE - OSPF6_LS_UPD_MIN_SIZE,
       0,
       ntohl (lsupd->lsa_number) /* 32 bits */
     );
@@ -1253,7 +1349,7 @@ ospf6_packet_examin (struct ospf6_header
     test = ospf6_lsaseq_examin
     (
       (struct ospf6_lsa_header *) ((caddr_t) oh + OSPF6_HEADER_SIZE + OSPF6_LS_ACK_MIN_SIZE),
-      bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_ACK_MIN_SIZE,
+      bytesdeclared - OSPF6_HEADER_SIZE - OSPF6_LS_ACK_MIN_SIZE,
       1,
       0
     );
@@ -1268,6 +1364,7 @@ ospf6_packet_examin (struct ospf6_header
   return test;
 }
 
+
 /* Verify particular fields of otherwise correct received OSPF packet to
    meet the requirements of RFC. */
 static int
@@ -1275,7 +1372,7 @@ ospf6_rxpacket_examin (struct ospf6_inte
 {
   char buf[2][INET_ADDRSTRLEN];
 
-  if (MSG_OK != ospf6_packet_examin (oh, bytesonwire))
+  if (MSG_OK != ospf6_packet_examin (oi, oh, bytesonwire))  
     return MSG_NG;
 
   /* Area-ID check */
@@ -1313,6 +1410,212 @@ ospf6_rxpacket_examin (struct ospf6_inte
   return MSG_OK;
 }
 
+
+static int
+ospf6_check_sha_digest(struct ospf6_interface *oi, struct ospf6_header *oh,
+                       struct ospfv3_crypt *ospf6_at,struct in6_addr *src)
+{
+  int i;
+  uint8_t local_dlen=hash_digest_length[oi->hash_algo];
+  uint8_t key_len; 
+  uint8_t auth_key_len;
+  size_t compr_authlen;
+  uint8_t Apad[local_dlen];
+  unsigned hash_algo;
+  u_char received_auth_data[local_dlen];
+  u_char output[local_dlen];
+  unsigned hash_error;
+  struct ospf6_neighbor *on;
+  oh->checksum=0;
+  struct keychain *keychain;
+  struct key *key;
+  char *ks;
+  char *auth_str = NULL;
+  u_int8_t compr_auth_str[OSPF6_AUTH_DATA_SIZE];
+  
+  /* Check crypto seqnum. As done in ospfv2 */
+  on = ospf6_neighbor_lookup (oh->router_id, oi);
+
+  if (on && ntohl(on->high_order_seqnum) > ntohl(ospf6_at->high_order_seqnum))
+  {
+    zlog_warn ("Interface %s: %s Bad High-order-sequence %d (expect %d)",
+               oi->interface->name, __func__,
+               ntohl(ospf6_at->high_order_seqnum), ntohl(on->ospf6_if->high_order_seqnum));
+    return 0;
+  }
+    
+  if (on && ntohl(on->high_order_seqnum) == ntohl(ospf6_at->high_order_seqnum)
+      && ntohl(on->low_order_seqnum) >= ntohl(ospf6_at->low_order_seqnum))
+  {
+    zlog_warn ("Interface %s: %s Bad Low-order-sequence %d (expect %d)",
+               oi->interface->name, __func__,
+               ntohl(ospf6_at->low_order_seqnum), ntohl(on->ospf6_if->low_order_seqnum));
+    return 0;
+  }
+
+  /* pick local key */
+  if (oi->key_chain)
+  {
+    if ((keychain = keychain_lookup (oi->key_chain)) == NULL)
+    {
+      zlog_debug ("key chain '%s' is configured, but does not exist", oi->key_chain);
+      return 0;
+    }
+    if ((key = key_lookup_for_accept (keychain, ntohs (ospf6_at->sa_id))) == NULL)
+    {
+      zlog_debug ("key %u lookup failed", ntohs (ospf6_at->sa_id));
+      return 0;
+    }
+    zlog_debug ("using keychain '%s', key %u for receiving", oi->key_chain, key->index);
+    auth_str = key->string;
+  }
+  if (auth_str == NULL)
+  {
+    zlog_debug ("authentication string lookup failed");
+    return 0;
+  }
+
+  auth_key_len = strlen(auth_str);
+  
+  /* As per RFC-6506 Sec 4.5, Apad is a value that is the same length as the hash
+   * output or message digest. The first 16 octets contain the IPv6 source address
+   * followed by the hexadecimal value 0x878FE1F3 repeated (L-16)/4 times.
+   * This implies that hash output is always a length of at least 16 octets.*/
+  
+  memset (Apad,0, sizeof(Apad));
+  memcpy (Apad,src, sizeof (struct in6_addr));	
+  memcpy (Apad + sizeof (struct in6_addr), hash_apad_sha512, local_dlen-16);
+
+  /* Method to (create ks) Function for appending CPID to Authentication key K to form Ks */
+  ks = malloc (auth_key_len + sizeof(CPID));
+  if (ks == NULL)
+    return 0;
+  memset(ks, 0, sizeof(ks));
+  memcpy(ks, auth_str, auth_key_len);
+  memcpy(ks + auth_key_len, &CPID, sizeof(CPID));
+
+  key_len = auth_key_len + sizeof(CPID);
+
+  memcpy (received_auth_data, ospf6_at->auth_data, local_dlen);
+  
+  /* OSPFv3 Authentication Process Starts */
+  hash_key_compress_rfc4822 (oi->hash_algo, ks, key_len, compr_auth_str, &compr_authlen);
+  memset (ospf6_at->auth_data, 0, sizeof(Apad));
+  memcpy (ospf6_at->auth_data, Apad, sizeof(Apad));
+  hash_error = hash_make_hmac (oi->hash_algo, oh, sizeof(oh), compr_auth_str, compr_authlen, output);
+  memcpy (ospf6_at->auth_data, output, hash_digest_length[oi->hash_algo]);
+
+  if (hash_error)
+  {
+    zlog_debug ("hash function returned error %u", hash_error);
+    return 0;
+  }
+  /* Compare the local and received digests */
+  if (memcmp (ospf6_at->auth_data , received_auth_data, hash_digest_length[oi->hash_algo]))
+  {
+    zlog_warn ("interface %s: %s digest mismatch", oi->interface->name, __func__);
+    return 0;
+  }
+    
+  /* save neighbor's crypt_seqnum */
+  if (on)
+  {
+    on->low_order_seqnum = ospf6_at->low_order_seqnum;
+    on->high_order_seqnum = ospf6_at->high_order_seqnum;
+  }
+  free(ks);
+  return 1;
+}
+
+static int
+ospf6_check_auth (struct ospf6_interface *oi, struct ospf6_header *oh,
+                  struct ospfv3_crypt *ospf6_at, struct in6_addr *src)
+{
+  struct ospf6_hello *hello;
+  struct ospf6_dbdesc *dbdesc;
+  u_int16_t iface_auth_type; 			//local auth type
+  u_int16_t pkt_auth_type = OSPF6_AUTH_NULL;   //received auth type
+  struct ospf6_neighbor *on;
+
+  on = ospf6_neighbor_lookup (oh->router_id, oi);
+  if (on == NULL)
+  {
+    zlog_debug ("Neighbor not found, ignore");
+    return;
+  }
+
+  hello = (struct ospf6_hello *)
+    ((caddr_t) oh + sizeof (struct ospf6_header));       
+
+  dbdesc = (struct ospf6_dbdesc *)
+    ((caddr_t) oh + sizeof (struct ospf6_header));       
+
+  /* case when AT Bit is set at sender but key is not specified,
+   * auth_type is considered to be NULL */
+  switch (oh->type)
+  {
+    case OSPF6_MESSAGE_TYPE_HELLO:
+    case OSPF6_MESSAGE_TYPE_DBDESC:
+         if((OSPF6_OPT_ISSET_AT(hello->options,OSPF6_OPT_AT) ||
+            OSPF6_OPT_ISSET_AT(dbdesc->options ,OSPF6_OPT_AT)) &&
+            (ospf6_at->auth_type == OSPF6_AUTH_CRYPTOGRAPHIC))  
+         {
+           pkt_auth_type =  OSPF6_AUTH_CRYPTOGRAPHIC;
+           on->is_set_at = TRUE;
+         }
+         break;
+    case OSPF6_MESSAGE_TYPE_LSREQ:
+    case OSPF6_MESSAGE_TYPE_LSUPDATE:
+    case OSPF6_MESSAGE_TYPE_LSACK:
+         if(on->is_set_at == TRUE)  
+          pkt_auth_type =  OSPF6_AUTH_CRYPTOGRAPHIC;
+         break;
+    default:
+         zlog_debug ("Unknown message");
+         break;
+  }
+  
+  switch (pkt_auth_type)
+  {
+    case OSPF6_AUTH_NULL: 
+         if (OSPF6_AUTH_NULL != (iface_auth_type = ospf6_auth_type (oi)))
+         {
+           if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+             zlog_warn ("interface %s: auth-type mismatch, local %s, rcvd Null", 
+                        oi->interface->name, LOOKUP(ospf6_auth_type_string, iface_auth_type));
+           return MSG_NG;
+         }
+         return MSG_OK;
+    case OSPF6_AUTH_CRYPTOGRAPHIC: 
+         if (OSPF6_AUTH_CRYPTOGRAPHIC != (iface_auth_type = ospf6_auth_type (oi)))
+         {
+           if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+             zlog_warn ("interface %s: auth-type mismatch, local %s, rcvd Cryptographic",
+               oi->interface->name, LOOKUP (ospf6_auth_type_string, iface_auth_type));
+           return MSG_NG;
+         }
+
+    /* As per RFC 6506 sec 4.2, Checksum verification should be omitted, if it 
+     * does not include a non-zero checksum, it will not be modified by the 
+     * receiver and simply be included in calculation of Authentication Trailer
+     * message digest */
+      
+    /* SHA crypto method can pass ospf6_packet_examin() */
+
+    if (! ospf6_check_sha_digest (oi, oh,ospf6_at,src))
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_warn ("interface %s: %s failed", oi->interface->name, __func__);
+      return MSG_NG;
+    }
+    return MSG_OK;
+    default:
+         if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+           zlog_warn ("interface %s: invalid packet auth-type (%02x)",
+                     oi->interface->name, pkt_auth_type);
+         return MSG_NG;
+  }
+}
+
 static void
 ospf6_lsupdate_recv (struct in6_addr *src, struct in6_addr *dst,
                      struct ospf6_interface *oi, struct ospf6_header *oh)
@@ -1533,6 +1836,7 @@ ospf6_receive (struct thread *thread)
   struct iovec iovector[2];
   struct ospf6_interface *oi;
   struct ospf6_header *oh;
+  struct ospfv3_crypt *ospf6_at;
 
   /* add next read thread */
   sockfd = THREAD_FD (thread);
@@ -1574,9 +1878,19 @@ ospf6_receive (struct thread *thread)
   if (ospf6_rxpacket_examin (oi, oh, len) != MSG_OK)
     return 0;
 
+  /* Check Authentication of data */
+  /* ospf6_at can create problem when AT bit is not set */
+
+  /* Value of ospf6_at for received packet */
+  ospf6_at = (struct ospfv3_crypt *)((caddr_t) oh + ntohs (oh->length)); 
+
+    if (ospf6_check_auth (oi, oh,ospf6_at,&src)!= MSG_OK)
+    return 0;
+
+ 
   /* Being here means, that no sizing/alignment issues were detected in
-     the input packet. This renders the additional checks performed below
-     and also in the type-specific dispatching functions a dead code,
+     the input packet.It also means that if Authentication is set for the
+     interface, it has been passed. This renders the additional checks performed 
+     below and also in the type-specific dispatching functions a dead code,
      which can be dismissed in a cleanup-focused review round later. */
 
   /* Log */
@@ -1592,10 +1906,10 @@ ospf6_receive (struct thread *thread)
       switch (oh->type)
         {
           case OSPF6_MESSAGE_TYPE_HELLO:
-            ospf6_hello_print (oh);
+            ospf6_hello_print (oh, ospf6_at);
             break;
           case OSPF6_MESSAGE_TYPE_DBDESC:
-            ospf6_dbdesc_print (oh);
+            ospf6_dbdesc_print (oh, ospf6_at);
             break;
           case OSPF6_MESSAGE_TYPE_LSREQ:
             ospf6_lsreq_print (oh);
@@ -1641,6 +1955,141 @@ ospf6_receive (struct thread *thread)
 }
 
 static void
+ospf6_make_sha_digest (struct in6_addr *src,struct ospf6_interface *oi,
+                       struct ospf6_header *oh, struct ospfv3_crypt *ospf6_at, char *auth_str)
+{
+  int i;
+  unsigned hash_algo;
+  uint8_t dlen=hash_digest_length[oi->hash_algo];
+  uint8_t Apad[dlen];
+  u_char output[dlen];
+  uint8_t auth_key_len;
+  size_t compr_authlen;
+  uint8_t key_len;
+  struct in6_addr src_temp;
+  u_int8_t compr_auth_str[OSPF6_AUTH_DATA_SIZE];
+  unsigned hash_error;
+  char *ks;
+  struct keychain *keychain;
+  struct key *key = NULL;
+ 
+  auth_key_len = strlen(auth_str);
+
+  /* As per RFC-6506, Apad is a value that is the same length as the hash output
+   * or message digest. The first 16 octets contain the IPv6 source address 
+   * followed by the hexadecimal value 0x878FE1F3 repeated (L-16)/4 times.
+   * This implies that hash output is always a length of at least 16 octets. */
+  memset(Apad,0, sizeof(Apad));
+  memset(&src_temp,0,sizeof(struct in6_addr));
+
+  if(src)
+    memcpy(Apad,src, sizeof (struct in6_addr));   
+  else
+    memcpy(Apad,&src_temp, sizeof (struct in6_addr));
+ 
+  memcpy(Apad + sizeof (struct in6_addr), hash_apad_sha512, dlen-16); 
+
+  /*Method to (create ks) Function for appending CPID to Authentication key K to form Ks*/
+  ks = malloc(auth_key_len+sizeof(CPID));
+  if (ks == NULL)
+    return 0;
+  memset(ks, 0, sizeof(ks));
+  memcpy(ks, auth_str, auth_key_len);
+  memcpy(ks + auth_key_len, &CPID, sizeof(CPID));
+  key_len = auth_key_len + sizeof(CPID);
+
+  /* OSPFv3 Authentication Process Starts*/
+  hash_key_compress_rfc4822 (oi->hash_algo, ks, key_len, compr_auth_str, &compr_authlen);
+  memcpy( ospf6_at->auth_data, Apad, sizeof(Apad));
+  hash_error = hash_make_hmac (oi->hash_algo, oh, sizeof(oh), compr_auth_str, compr_authlen, output);
+  memcpy( ospf6_at->auth_data, output, hash_digest_length[oi->hash_algo] );
+
+  if (hash_error)
+  {
+    zlog_debug ("hash function returned error %u", hash_error);
+    return 0;
+  }
+  free(ks);
+}
+
+
+static void
+ospf6_make_auth (struct in6_addr *src, struct ospf6_interface *oi,
+                 struct ospf6_header *oh, struct ospfv3_crypt *ospf6_at)
+{
+  u_int32_t t;
+  ospf6_at->auth_type = OSPF6_AUTH_CRYPTOGRAPHIC ;  /* Setting of auth type */
+  ospf6_at->reserved = 0;                           /* Setting of reserved field to 0 */
+  struct key *key = NULL;
+  char *auth_str = NULL;
+
+  if (ospf6_at->auth_type == OSPF6_AUTH_CRYPTOGRAPHIC)
+  {
+    if (oi->key_chain)
+    {
+      struct keychain *keychain;
+      keychain = keychain_lookup (oi->key_chain);
+      if (keychain)
+      {
+        key = key_lookup_for_send (keychain);
+      }
+      else
+      {
+        zlog_debug ("key chain '%s' is configured, but does not exist", oi->key_chain);
+      }
+    }
+    /* Pick correct auth string for sending */
+    if (key && key->string)
+    {
+      zlog_debug ("using keychain '%s'", oi->key_chain);
+      auth_str = key->string;
+    }
+    if (auth_str == NULL)
+    {
+      zlog_debug ("authentication string lookup failed");
+      return -1;
+    }
+
+    ospf6_at->sa_id = htons (key->index);
+  }
+
+  /* Similar to ospfv2 sequence number code */
+  t = (time(NULL) & 0xFFFFFFFF);
+  if (t > oi->low_order_seqnum)
+    oi->low_order_seqnum = t;
+  else
+    oi->low_order_seqnum++;
+
+  /* As per RFC-6506 section 4.1.1 "Sequence Number Wrap" */
+
+  /* For lower order sequence wrap */
+  if(oi->low_order_seqnum == 0xFFFFFFFF)
+  {
+    oi->high_order_seqnum++;
+    oi->low_order_seqnum=0;
+  }
+  /* For higher order sequence wrap...if higher order is filled, reset higher
+   * order and lower order and reset all the keys to 0 */
+  if(oi->high_order_seqnum == 0xFFFFFFFF && oi->low_order_seqnum == 0xFFFFFFFF)
+  {
+    oi->high_order_seqnum = 0;
+    oi->low_order_seqnum = 0;
+    if (oi->key_chain)
+      XFREE (MTYPE_OSPF6_CRYPT_KEY, oi->key_chain);
+  }
+
+  ospf6_at->low_order_seqnum = htonl (oi->low_order_seqnum);
+  ospf6_at->high_order_seqnum = htonl (oi->high_order_seqnum);
+  /* Authentication data length = Authentication trailer (16 octet) + 
+                                  Digest (Algorithm specific digest length) */
+  ospf6_at->auth_data_length = htons (AUTH_TRAILER_HEADER + hash_digest_length[oi->hash_algo]);
+  ospf6_make_sha_digest (src,oi,oh,ospf6_at,auth_str);
+
+}
+
+
+static void
 ospf6_send (struct in6_addr *src, struct in6_addr *dst,
             struct ospf6_interface *oi, struct ospf6_header *oh)
 {
@@ -1648,11 +2097,11 @@ ospf6_send (struct in6_addr *src, struct
   char srcname[64], dstname[64];
   struct iovec iovector[2];
 
-  /* initialize */
-  iovector[0].iov_base = (caddr_t) oh;
-  iovector[0].iov_len = ntohs (oh->length);
-  iovector[1].iov_base = NULL;
-  iovector[1].iov_len = 0;
+  struct ospfv3_crypt *ospf6_at ;
+
+  /* Append the Authentication Trailer to OSPFv3 packet */
+
+  ospf6_at = (struct ospfv3_crypt *)((caddr_t) oh + ntohs (oh->length));
 
   /* fill OSPF header */
   oh->version = OSPFV3_VERSION;
@@ -1664,6 +2113,31 @@ ospf6_send (struct in6_addr *src, struct
   oh->instance_id = oi->instance_id;
   oh->reserved = 0;
 
+
+  if(ospf6_auth_type(oi))
+  {
+    /* As per RFC 6506 sec 4.2, Checksum should be set to 0 prior to 
+    calculation of Authentication Trailer message digest */
+
+    oh->checksum = 0; 
+
+    ospf6_make_auth(src,oi, oh,ospf6_at);
+
+    /* initialize */
+    iovector[0].iov_base = (caddr_t) oh;
+    iovector[0].iov_len = ntohs(oh->length) + ntohs (ospf6_at->auth_data_length);
+    iovector[1].iov_base = NULL;
+    iovector[1].iov_len = 0;            
+  }
+  else
+  {  
+    ospf6_at->auth_type = OSPF6_AUTH_NULL;
+    /* initialize */
+    iovector[0].iov_base = (caddr_t) oh;
+    iovector[0].iov_len = ntohs (oh->length);
+    iovector[1].iov_base = NULL;
+    iovector[1].iov_len = 0;
+  }
   /* Log */
   if (IS_OSPF6_DEBUG_MESSAGE (oh->type, SEND))
     {
@@ -1680,10 +2154,10 @@ ospf6_send (struct in6_addr *src, struct
       switch (oh->type)
         {
           case OSPF6_MESSAGE_TYPE_HELLO:
-            ospf6_hello_print (oh);
+            ospf6_hello_print (oh,ospf6_at);
             break;
           case OSPF6_MESSAGE_TYPE_DBDESC:
-            ospf6_dbdesc_print (oh);
+            ospf6_dbdesc_print (oh,ospf6_at);
             break;
           case OSPF6_MESSAGE_TYPE_LSREQ:
             ospf6_lsreq_print (oh);
@@ -1703,9 +2177,16 @@ ospf6_send (struct in6_addr *src, struct
 
   /* send message */
   len = ospf6_sendmsg (src, dst, &oi->interface->ifindex, iovector);
-  if (len != ntohs (oh->length))
+
+  if(ospf6_auth_type(oi))
+  {
+    if (len != (ntohs (oh->length)+ ntohs (ospf6_at->auth_data_length)))
+      zlog_err ("Could not send entire message");
+  }
+  else
+  { 
+     if (len != ntohs (oh->length))
+       zlog_err ("Could not send entire message");
+  }
+}
 
 static uint32_t
 ospf6_packet_max(struct ospf6_interface *oi)
@@ -1714,6 +2195,7 @@ ospf6_packet_max(struct ospf6_interface
   return oi->ifmtu - (sizeof (struct ip6_hdr));
 }
 
+
 int
 ospf6_hello_send (struct thread *thread)
 {
@@ -1748,6 +2230,12 @@ ospf6_hello_send (struct thread *thread)
   hello->options[0] = oi->area->options[0];
   hello->options[1] = oi->area->options[1];
   hello->options[2] = oi->area->options[2];
+
+  if(oi->auth_type)
+  {
+    OSPF6_OPT_SET_AT(hello->options, OSPF6_OPT_AT);
+  }
+
   hello->hello_interval = htons (oi->hello_interval);
   hello->dead_interval = htons (oi->dead_interval);
   hello->drouter = oi->drouter;
@@ -1794,7 +2282,7 @@ ospf6_dbdesc_send (struct thread *thread
     {
       if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_DBDESC, SEND))
         zlog_debug ("Quit to send DbDesc to neighbor %s state %s",
+      on->name, ospf6_neighbor_state_str[on->state]);
+      on->name, LOOKUP (ospf6_neighbor_state_str, on->state));
       return 0;
     }
 
@@ -1821,6 +2309,12 @@ ospf6_dbdesc_send (struct thread *thread
   dbdesc->options[0] = on->ospf6_if->area->options[0];
   dbdesc->options[1] = on->ospf6_if->area->options[1];
   dbdesc->options[2] = on->ospf6_if->area->options[2];
+
+  if(on->ospf6_if->auth_type)
+  {
+        OSPF6_OPT_SET_AT(dbdesc->options, OSPF6_OPT_AT);
+  }
+
   dbdesc->ifmtu = htons (on->ospf6_if->ifmtu);
   dbdesc->bits = on->dbdesc_bits;
   dbdesc->seqnum = htonl (on->dbdesc_seqnum);
@@ -1853,7 +2347,6 @@ ospf6_dbdesc_send (struct thread *thread
               on->ospf6_if, oh);
   return 0;
 }
-
 int
 ospf6_dbdesc_send_newone (struct thread *thread)
 {
diff -upwbNr quagga-0.99.21/ospf6d/ospf6_message.h quagga-rfc6506/ospf6d/ospf6_message.h
--- quagga-0.99.21/ospf6d/ospf6_message.h	2012-03-24 01:13:20.000000000 +0530
+++ quagga-rfc6506/ospf6d/ospf6_message.h	2013-10-25 15:48:12.000000000 +0530
@@ -60,6 +60,26 @@ struct ospf6_header
 
 #define OSPF6_MESSAGE_END(H) ((caddr_t) (H) + ntohs ((H)->length))
 
+#define OSPF6_AUTH_DATA_SIZE     64U
+#define BLOCK_SIZE               128U 
+#define LENGTH_OF_HASH           64U 
+#define AUTH_TRAILER_HEADER      16U  
+#define OSPF6_AUTH_NULL          0    
+#define OSPF6_AUTH_CRYPTOGRAPHIC 1   
+
+/* Authentication Trailer Structure */
+struct ospfv3_crypt             
+{
+  u_int16_t   auth_type; 
+  u_int16_t   auth_data_length;
+  u_int16_t   reserved;
+  u_int16_t   sa_id;
+  u_int32_t   high_order_seqnum;
+  u_int32_t   low_order_seqnum;
+  u_char auth_data[OSPF6_AUTH_DATA_SIZE];
+
+};
+
 /* Hello */
 #define OSPF6_HELLO_MIN_SIZE                  20U
 struct ospf6_hello
@@ -116,8 +136,8 @@ struct ospf6_lsupdate
 /* It is just a sequence of LSA Headers */
 
 /* Function definition */
-extern void ospf6_hello_print (struct ospf6_header *);
-extern void ospf6_dbdesc_print (struct ospf6_header *);
+extern void ospf6_hello_print (struct ospf6_header * , struct ospfv3_crypt *);   
+extern void ospf6_dbdesc_print (struct ospf6_header * , struct ospfv3_crypt *);
 extern void ospf6_lsreq_print (struct ospf6_header *);
 extern void ospf6_lsupdate_print (struct ospf6_header *);
 extern void ospf6_lsack_print (struct ospf6_header *);
diff -upwbNr quagga-0.99.21/ospf6d/ospf6_neighbor.c quagga-rfc6506/ospf6d/ospf6_neighbor.c
--- quagga-0.99.21/ospf6d/ospf6_neighbor.c	2010-08-12 18:29:32.000000000 +0530
+++ quagga-rfc6506/ospf6d/ospf6_neighbor.c	2013-10-25 15:42:56.462519549 +0530
@@ -46,6 +46,9 @@ const char *ospf6_neighbor_state_str[] =
 { "None", "Down", "Attempt", "Init", "Twoway", "ExStart", "ExChange",
   "Loading", "Full", NULL };
 
+const size_t ospf6_neighbor_state_str_max = sizeof (ospf6_neighbor_state_str) /
+  sizeof (ospf6_neighbor_state_str[0]);
+
 int
 ospf6_neighbor_cmp (void *va, void *vb)
 {
@@ -69,8 +72,11 @@ ospf6_neighbor_lookup (u_int32_t router_
 }
 
 /* create ospf6_neighbor */
+
+/* ospf6_at added as parameter in order to update sequence no. */
+
 struct ospf6_neighbor *
-ospf6_neighbor_create (u_int32_t router_id, struct ospf6_interface *oi)
+ospf6_neighbor_create (u_int32_t router_id, struct ospf6_interface *oi, struct ospfv3_crypt *ospf6_at)   
 {
   struct ospf6_neighbor *on;
   char buf[16];
@@ -100,6 +106,13 @@ ospf6_neighbor_create (u_int32_t router_
   on->lsreq_list = ospf6_lsdb_create (on);
   on->lsupdate_list = ospf6_lsdb_create (on);
   on->lsack_list = ospf6_lsdb_create (on);
+  /* if Authentication is enabled, auth_type will be non-zero value, it will update the higher and lower cryt seq no. */
+  if(ospf6_at->auth_type)
+  {
+    on->low_order_seqnum = ospf6_at->low_order_seqnum;
+    on->high_order_seqnum = ospf6_at->high_order_seqnum;
+    on->is_set_at = TRUE;
+  }
 
   listnode_add_sort (oi->neighbor_list, on);
   return on;
diff -upwbNr quagga-0.99.21/ospf6d/ospf6_neighbor.h quagga-rfc6506/ospf6d/ospf6_neighbor.h
--- quagga-0.99.21/ospf6d/ospf6_neighbor.h	2010-08-12 18:29:32.000000000 +0530
+++ quagga-rfc6506/ospf6d/ospf6_neighbor.h	2013-10-25 15:44:10.202518358 +0530
@@ -33,6 +33,9 @@ extern unsigned char conf_debug_ospf6_ne
 #define IS_OSPF6_DEBUG_NEIGHBOR(level) \
   (conf_debug_ospf6_neighbor & OSPF6_DEBUG_NEIGHBOR_ ## level)
 
+#define TRUE 1
+#define FALSE 0
+
 /* Neighbor structure */
 struct ospf6_neighbor
 {
@@ -93,6 +96,10 @@ struct ospf6_neighbor
   struct thread *thread_send_lsreq;
   struct thread *thread_send_lsupdate;
   struct thread *thread_send_lsack;
+
+  u_int32_t high_order_seqnum; /* higher order Cryptographic Sequence Number */
+  u_int32_t low_order_seqnum;  /* lower order Cryptographic Sequence Number */
+  u_int8_t is_set_at;          /* information of AT bit in hello and db packet */
 };
 
 /* Neighbor state */
@@ -106,7 +113,7 @@ struct ospf6_neighbor
 #define OSPF6_NEIGHBOR_FULL     8
 
 extern const char *ospf6_neighbor_state_str[];
-
+extern const size_t ospf6_neighbor_state_str_max;
 
 /* Function Prototypes */
 int ospf6_neighbor_cmp (void *va, void *vb);
@@ -115,7 +122,7 @@ void ospf6_neighbor_dbex_init (struct os
 struct ospf6_neighbor *ospf6_neighbor_lookup (u_int32_t,
                                               struct ospf6_interface *);
 struct ospf6_neighbor *ospf6_neighbor_create (u_int32_t,
-                                              struct ospf6_interface *);
+                                              struct ospf6_interface *, struct ospfv3_crypt *); 
 void ospf6_neighbor_delete (struct ospf6_neighbor *);
 
 /* Neighbor event */
diff -upwbNr quagga-0.99.21/ospf6d/ospf6_proto.c quagga-rfc6506/ospf6d/ospf6_proto.c
--- quagga-0.99.21/ospf6d/ospf6_proto.c	2012-03-24 01:13:20.000000000 +0530
+++ quagga-rfc6506/ospf6d/ospf6_proto.c	2013-07-10 10:16:00.000000000 +0530
@@ -71,14 +71,17 @@ ospf6_capability_printbuf (char capabili
 void
 ospf6_options_printbuf (u_char *options, char *buf, int size)
 {
-  const char *dc, *r, *n, *mc, *e, *v6;
+  const char *dc, *r, *n, *mc, *e, *v6, *at;
+
   dc = (OSPF6_OPT_ISSET (options, OSPF6_OPT_DC) ? "DC" : "--");
   r  = (OSPF6_OPT_ISSET (options, OSPF6_OPT_R)  ? "R"  : "-" );
   n  = (OSPF6_OPT_ISSET (options, OSPF6_OPT_N)  ? "N"  : "-" );
   mc = (OSPF6_OPT_ISSET (options, OSPF6_OPT_MC) ? "MC" : "--");
   e  = (OSPF6_OPT_ISSET (options, OSPF6_OPT_E)  ? "E"  : "-" );
   v6 = (OSPF6_OPT_ISSET (options, OSPF6_OPT_V6) ? "V6" : "--");
-  snprintf (buf, size, "%s|%s|%s|%s|%s|%s", dc, r, n, mc, e, v6);
-}
 
+  at = (OSPF6_OPT_ISSET_AT (options, OSPF6_OPT_AT) ? "AT" : "--");
+  snprintf (buf, size, "|%s|-|--|--|--|%s|%s|%s|%s|%s|%s", at, dc, r, n, mc, e, v6);
+
+}
 
diff -upwbNr quagga-0.99.21/ospf6d/ospf6_proto.h quagga-rfc6506/ospf6d/ospf6_proto.h
--- quagga-0.99.21/ospf6d/ospf6_proto.h	2012-03-24 01:13:20.000000000 +0530
+++ quagga-rfc6506/ospf6d/ospf6_proto.h	2013-07-10 10:16:00.000000000 +0530
@@ -60,6 +60,12 @@
 
 /* OSPF options */
 /* present in HELLO, DD, LSA */
+#define OSPF6_OPT_SET_AT(x,opt)   ((x)[1] |=  (opt))
+#define OSPF6_OPT_ISSET_AT(x,opt) ((x)[1] &   (opt))
+#define OSPF6_OPT_CLEAR_AT(x,opt) ((x)[1] &= ~(opt))
+
+/* OSPF options */
+/* present in HELLO, DD, LSA */
 #define OSPF6_OPT_SET(x,opt)   ((x)[2] |=  (opt))
 #define OSPF6_OPT_ISSET(x,opt) ((x)[2] &   (opt))
 #define OSPF6_OPT_CLEAR(x,opt) ((x)[2] &= ~(opt))
@@ -72,6 +78,8 @@
 #define OSPF6_OPT_E  (1 << 1)   /* AS External Capability */
 #define OSPF6_OPT_V6 (1 << 0)   /* IPv6 forwarding Capability */
 
+#define OSPF6_OPT_AT (1 << 2)   /* Authentication Capability */
+
 /* OSPF6 Prefix */
 #define OSPF6_PREFIX_MIN_SIZE                  4U /* .length == 0 */
 struct ospf6_prefix


Thanks & Regards
Jyotsna Priya
=====-----=====-----=====
Notice: The information contained in this e-mail
message and/or attachments to it may contain 
confidential or privileged information. If you are 
not the intended recipient, any dissemination, use, 
review, distribution, printing or copying of the 
information contained in this e-mail message 
and/or attachments to it are strictly prohibited. If 
you have received this communication in error, 
please notify us by reply e-mail or telephone and 
immediately and permanently delete the message 
and any attachments. Thank you







More information about the Quagga-dev mailing list