]> git.puffer.fish Git - mirror/frr.git/commitdiff
[ospfd]: add support for RFC 5709 HMAC-SHA Auth 14398/head
authorMahdi Varasteh <varasteh@amnesh.ir>
Tue, 12 Sep 2023 11:39:44 +0000 (15:09 +0330)
committerMahdi Varasteh <varasteh@amnesh.ir>
Sat, 16 Sep 2023 04:08:23 +0000 (07:38 +0330)
This patch includes:
* Implementation of RFC 5709 support in OSPF. Using
openssl library and FRR key-chain,
one can use SHA1, SHA256, SHA384, SHA512 and
keyed-MD5( backward compatibility with RFC 2328) HMAC algs.
* Updating documentation of OSPF
* add topotests for new HMAC algorithms

Signed-off-by: Mahdi Varasteh <varasteh@amnesh.ir>
15 files changed:
doc/user/ospfd.rst
ospfd/ospf_auth.c [new file with mode: 0644]
ospfd/ospf_auth.h [new file with mode: 0644]
ospfd/ospf_errors.c
ospfd/ospf_errors.h
ospfd/ospf_interface.c
ospfd/ospf_interface.h
ospfd/ospf_main.c
ospfd/ospf_packet.c
ospfd/ospf_vty.c
ospfd/subdir.am
python/xref2vtysh.py
tests/topotests/lib/ospf.py
tests/topotests/ospf_basic_functionality/test_ospf_authentication.py
vtysh/vtysh.h

index b61c9448db8723bf95f2b071c71d8e32842fcf62..26b2b43971b6ce8571c571266f230a6efaa87306 100644 (file)
@@ -599,6 +599,38 @@ Interfaces
    KEY is the actual message digest key, of up to 16 chars (larger strings will
    be truncated), and is associated with the given KEYID.
 
+.. clicmd:: ip ospf authentication key-chain KEYCHAIN
+
+   Specify that HMAC cryptographic authentication must be used on this interface
+   using a key chain. Overrides any authentication enabled on a per-area basis
+   (:clicmd:`area A.B.C.D authentication message-digest`)
+
+   * ``KEYCHAIN``: Specifies the name of the key chain that contains the authentication
+   key(s) and cryptographic algorithms to be used for OSPF authentication. The key chain
+   is a logical container that holds one or more authentication keys,
+   allowing for key rotation and management.
+
+   Note that OSPF HMAC cryptographic authentication requires that time never go backwards
+   (correct time is NOT important, only that it never goes backwards), even
+   across resets, if ospfd is to be able to promptly reestablish adjacencies
+   with its neighbours after restarts/reboots. The host should have system time
+   be set at boot from an external or non-volatile source (e.g. battery backed
+   clock, NTP, etc.) or else the system clock should be periodically saved to
+   non-volatile storage and restored at boot if HMAC cryptographic authentication is to be
+   expected to work reliably.
+
+   Example:
+
+   .. code:: frr
+
+      r1(config)#key chain temp
+      r1(config-keychain)#key 13
+      r1(config-keychain-key)#key-string ospf
+      r1(config-keychain-key)#cryptographic-algorithm hmac-sha-256
+      r1(config)#int eth0
+      r1(config-if)#ip ospf authentication key-chain temp
+      r1(config-if)#ip ospf area 0
+
 .. clicmd:: ip ospf cost (1-65535)
 
 
diff --git a/ospfd/ospf_auth.c b/ospfd/ospf_auth.c
new file mode 100644 (file)
index 0000000..2d13d4e
--- /dev/null
@@ -0,0 +1,705 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2023 Amnesh Inc.
+ *                    Mahdi Varasteh
+ */
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "if.h"
+#include "checksum.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_errors.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_auth.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_packet.h"
+#include "ospfd/ospf_network.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_bfd.h"
+#include "ospfd/ospf_gr.h"
+#ifdef CRYPTO_INTERNAL
+#include "sha256.h"
+#include "md5.h"
+#endif
+
+const uint8_t ospf_auth_apad[KEYCHAIN_MAX_HASH_SIZE] = {
+       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
+};
+
+static int ospf_check_sum(struct ospf_header *ospfh)
+{
+       uint32_t ret;
+       uint16_t sum;
+
+       /* clear auth_data for checksum. */
+       memset(ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE);
+
+       /* keep checksum and clear. */
+       sum = ospfh->checksum;
+       memset(&ospfh->checksum, 0, sizeof(uint16_t));
+
+       /* calculate checksum. */
+       ret = in_cksum(ospfh, ntohs(ospfh->length));
+
+       if (ret != sum) {
+               zlog_info("%s: checksum mismatch, my %X, his %X", __func__, ret,
+                         sum);
+               return 0;
+       }
+
+       return 1;
+}
+
+#ifdef CRYPTO_OPENSSL
+static const EVP_MD *ospf_auth_get_openssl_evp_md_from_key(struct key *key)
+{
+       if (key->hash_algo == KEYCHAIN_ALGO_HMAC_SHA1)
+               return EVP_get_digestbyname("sha1");
+       else if (key->hash_algo == KEYCHAIN_ALGO_HMAC_SHA256)
+               return EVP_get_digestbyname("sha256");
+       else if (key->hash_algo == KEYCHAIN_ALGO_HMAC_SHA384)
+               return EVP_get_digestbyname("sha384");
+       else if (key->hash_algo == KEYCHAIN_ALGO_HMAC_SHA512)
+               return EVP_get_digestbyname("sha512");
+       return NULL;
+}
+#endif
+
+static int ospf_auth_check_hmac_sha_digest(struct ospf_interface *oi,
+                                          struct ospf_header *ospfh,
+                                          struct ip *iph,
+                                          struct key *key)
+{
+       unsigned char digest[KEYCHAIN_MAX_HASH_SIZE];
+       struct ospf_neighbor *nbr;
+       uint16_t length = ntohs(ospfh->length);
+       uint16_t hash_length = keychain_get_hash_len(key->hash_algo);
+#ifdef CRYPTO_OPENSSL
+       unsigned int openssl_hash_length = hash_length;
+       HMAC_CTX *ctx;
+       const EVP_MD *md_alg = ospf_auth_get_openssl_evp_md_from_key(key);
+
+       if (!md_alg) {
+               flog_warn(EC_OSPF_AUTH,
+                         "interface %s: invalid HMAC algorithm, Router-ID: %pI4",
+                         IF_NAME(oi), &ospfh->router_id);
+               return 0;
+       }
+#elif CRYPTO_INTERNAL
+       HMAC_SHA256_CTX ctx;
+
+       if (key->hash_algo != KEYCHAIN_ALGO_HMAC_SHA256) {
+               flog_warn(EC_OSPF_AUTH,
+                         "interface %s: HMAC algorithm not supported, Router-ID: %pI4",
+                         IF_NAME(oi), &ospfh->router_id);
+               return 0;
+       }
+#endif
+       /* check crypto seqnum. */
+       nbr = ospf_nbr_lookup(oi, iph, ospfh);
+
+       if (nbr &&
+           ntohl(nbr->crypt_seqnum) > ntohl(ospfh->u.crypt.crypt_seqnum)) {
+               flog_warn(EC_OSPF_AUTH,
+                         "interface %s: ospf_check_hmac_sha bad sequence %u (expect %d), Router-ID: %pI4",
+                         IF_NAME(oi), ntohl(ospfh->u.crypt.crypt_seqnum),
+                         ntohl(nbr->crypt_seqnum), &ospfh->router_id);
+               return 0;
+       }
+#ifdef CRYPTO_OPENSSL
+       ctx = HMAC_CTX_new();
+       HMAC_Init_ex(ctx, key->string, strlen(key->string), md_alg, NULL);
+       HMAC_Update(ctx, (const unsigned char *)ospfh, length);
+       HMAC_Update(ctx, (const unsigned char *)ospf_auth_apad, hash_length);
+       HMAC_Final(ctx, digest, &openssl_hash_length);
+       HMAC_CTX_free(ctx);
+#elif CRYPTO_INTERNAL
+       memset(&ctx, 0, sizeof(ctx));
+       HMAC__SHA256_Init(&ctx, key->string, strlen(key->string));
+       HMAC__SHA256_Update(&ctx, ospfh, length);
+       HMAC__SHA256_Update(&ctx, ospf_auth_apad, hash_length);
+       HMAC__SHA256_Final(digest, &ctx);
+#endif
+       if (memcmp((caddr_t)ospfh + length, digest, hash_length)) {
+               flog_warn(EC_OSPF_AUTH,
+                         "interface %s: ospf_check_hmac_sha checksum mismatch %u, Router-ID: %pI4",
+                         IF_NAME(oi), length, &ospfh->router_id);
+               return 0;
+       }
+       if (nbr)
+               nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum;
+       return 1;
+}
+
+static int ospf_auth_check_md5_digest(struct ospf_interface *oi,
+                                     struct ospf_header *ospfh, struct ip *iph, struct key *key)
+{
+#ifdef CRYPTO_OPENSSL
+       EVP_MD_CTX *ctx;
+#elif CRYPTO_INTERNAL
+       MD5_CTX ctx;
+#endif
+       char auth_key[OSPF_AUTH_MD5_SIZE + 1];
+       unsigned char digest[OSPF_AUTH_MD5_SIZE];
+       struct ospf_neighbor *nbr;
+       struct crypt_key *ck = NULL;
+       uint16_t length = ntohs(ospfh->length);
+
+       if (key == NULL) {
+               ck = ospf_crypt_key_lookup(OSPF_IF_PARAM(oi, auth_crypt),
+                                  ospfh->u.crypt.key_id);
+               if (ck == NULL) {
+                       flog_warn(
+                               EC_OSPF_AUTH,
+                               "interface %s: %s no key %d, Router-ID: %pI4",
+                               IF_NAME(oi), __func__, ospfh->u.crypt.key_id, &ospfh->router_id);
+                       return 0;
+               }
+       }
+       /* check crypto seqnum. */
+       nbr = ospf_nbr_lookup(oi, iph, ospfh);
+
+       if (nbr &&
+           ntohl(nbr->crypt_seqnum) > ntohl(ospfh->u.crypt.crypt_seqnum)) {
+               flog_warn(EC_OSPF_AUTH,
+                         "interface %s: %s bad sequence %d (expect %d), Router-ID: %pI4",
+                         IF_NAME(oi), __func__, ntohl(ospfh->u.crypt.crypt_seqnum),
+                         ntohl(nbr->crypt_seqnum), &ospfh->router_id);
+               return 0;
+       }
+
+       memset(auth_key, 0, OSPF_AUTH_MD5_SIZE + 1);
+       if (ck == NULL)
+               strlcpy(auth_key, key->string, OSPF_AUTH_MD5_SIZE + 1);
+       else
+               strlcpy(auth_key, (char *)ck->auth_key, OSPF_AUTH_MD5_SIZE + 1);
+       /* Generate a digest for the ospf packet - their digest + our digest. */
+#ifdef CRYPTO_OPENSSL
+       unsigned int md5_size = OSPF_AUTH_MD5_SIZE;
+
+       ctx = EVP_MD_CTX_new();
+       EVP_DigestInit(ctx, EVP_md5());
+       EVP_DigestUpdate(ctx, ospfh, length);
+       EVP_DigestUpdate(ctx, auth_key, OSPF_AUTH_MD5_SIZE);
+       EVP_DigestFinal(ctx, digest, &md5_size);
+       EVP_MD_CTX_free(ctx);
+#elif CRYPTO_INTERNAL
+       memset(&ctx, 0, sizeof(ctx));
+       MD5Init(&ctx);
+       MD5Update(&ctx, ospfh, length);
+       MD5Update(&ctx, auth_key, OSPF_AUTH_MD5_SIZE);
+       MD5Final(digest, &ctx);
+#endif
+
+       /* compare the two */
+       if (memcmp((caddr_t)ospfh + length, digest, OSPF_AUTH_MD5_SIZE)) {
+               flog_warn(EC_OSPF_AUTH,
+                         "interface %s: ospf_check_md5 checksum mismatch, Router-ID: %pI4",
+                         IF_NAME(oi), &ospfh->router_id);
+               return 0;
+       }
+
+       /* save neighbor's crypt_seqnum */
+       if (nbr)
+               nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum;
+       return 1;
+}
+
+static int ospf_auth_make_md5_digest(struct ospf_interface *oi,
+                                    struct ospf_packet *op, struct key *key)
+{
+       void *ibuf;
+       struct ospf_header *ospfh;
+       unsigned char digest[OSPF_AUTH_MD5_SIZE];
+       uint16_t length;
+#ifdef CRYPTO_OPENSSL
+       EVP_MD_CTX *ctx;
+#elif CRYPTO_INTERNAL
+       MD5_CTX ctx;
+#endif
+       char auth_key[OSPF_AUTH_MD5_SIZE + 1];
+
+       memset(auth_key, 0, OSPF_AUTH_MD5_SIZE + 1);
+       strlcpy(auth_key, key->string, OSPF_AUTH_MD5_SIZE + 1);
+       ibuf = STREAM_DATA(op->s);
+       ospfh = (struct ospf_header *)ibuf;
+       length = ntohs(ospfh->length);
+       /* Generate a digest for the ospf packet - their digest + our digest. */
+#ifdef CRYPTO_OPENSSL
+       unsigned int md5_size = OSPF_AUTH_MD5_SIZE;
+
+       ctx = EVP_MD_CTX_new();
+       EVP_DigestInit(ctx, EVP_md5());
+       EVP_DigestUpdate(ctx, ospfh, length);
+       EVP_DigestUpdate(ctx, auth_key, OSPF_AUTH_MD5_SIZE);
+       EVP_DigestFinal(ctx, digest, &md5_size);
+       EVP_MD_CTX_free(ctx);
+#elif CRYPTO_INTERNAL
+       memset(&ctx, 0, sizeof(ctx));
+       MD5Init(&ctx);
+       MD5Update(&ctx, ospfh, length);
+       MD5Update(&ctx, auth_key, OSPF_AUTH_MD5_SIZE);
+       MD5Final(digest, &ctx);
+#endif
+
+       stream_put(op->s, digest, OSPF_AUTH_MD5_SIZE);
+
+       op->length = ntohs(ospfh->length) + OSPF_AUTH_MD5_SIZE;
+
+       if (stream_get_endp(op->s) != op->length)
+               /* XXX size_t */
+               flog_warn(EC_OSPF_AUTH,
+                         "%s: length mismatch stream %lu ospf_packet %u, Router-ID %pI4",
+                         __func__, (unsigned long)stream_get_endp(op->s),
+                         op->length, &ospfh->router_id);
+
+       return OSPF_AUTH_MD5_SIZE;
+}
+
+static int ospf_auth_make_hmac_sha_digest(struct ospf_interface *oi,
+                                         struct ospf_packet *op,
+                                         struct key *key)
+{
+       void *ibuf;
+       struct ospf_header *ospfh;
+       unsigned char digest[KEYCHAIN_MAX_HASH_SIZE] = { 0 };
+       uint16_t hash_length = keychain_get_hash_len(key->hash_algo);
+
+       ibuf = STREAM_DATA(op->s);
+       ospfh = (struct ospf_header *)ibuf;
+#ifdef CRYPTO_OPENSSL
+       unsigned int openssl_hash_length = hash_length;
+       HMAC_CTX *ctx;
+       const EVP_MD *md_alg = ospf_auth_get_openssl_evp_md_from_key(key);
+
+       if (!md_alg) {
+               flog_warn(EC_OSPF_AUTH,
+                         "interface %s: invalid HMAC algorithm, Router-ID: %pI4",
+                         IF_NAME(oi), &ospfh->router_id);
+               return 0;
+       }
+#elif CRYPTO_INTERNAL
+       HMAC_SHA256_CTX ctx;
+
+       if (key->hash_algo != KEYCHAIN_ALGO_HMAC_SHA256) {
+               flog_warn(EC_OSPF_AUTH,
+                         "interface %s: HMAC algorithm not supported, Router-ID: %pI4",
+                         IF_NAME(oi), &ospfh->router_id);
+               return 0;
+       }
+#endif
+#ifdef CRYPTO_OPENSSL
+       ctx = HMAC_CTX_new();
+       HMAC_Init_ex(ctx, key->string, strlen(key->string), md_alg, NULL);
+       HMAC_Update(ctx, (const unsigned char *)ospfh, ntohs(ospfh->length));
+       HMAC_Update(ctx, (const unsigned char *)ospf_auth_apad, hash_length);
+       HMAC_Final(ctx, digest, &openssl_hash_length);
+       HMAC_CTX_free(ctx);
+#elif CRYPTO_INTERNAL
+       memset(&ctx, 0, sizeof(ctx));
+       HMAC__SHA256_Init(&ctx, key->string, strlen(key->string));
+       HMAC__SHA256_Update(&ctx, ospfh, ntohs(ospfh->length));
+       HMAC__SHA256_Update(&ctx, ospf_auth_apad, hash_length);
+       HMAC__SHA256_Final(digest, &ctx);
+#endif
+       stream_put(op->s, digest, hash_length);
+
+       op->length = ntohs(ospfh->length) + hash_length;
+
+       if (stream_get_endp(op->s) != op->length)
+               /* XXX size_t */
+               flog_warn(EC_OSPF_AUTH,
+                         "%s: length mismatch stream %lu ospf_packet %u, Router-ID %pI4",
+                         __func__, (unsigned long)stream_get_endp(op->s),
+                         op->length, &ospfh->router_id);
+
+       return hash_length;
+}
+
+int ospf_auth_check_digest(struct ospf_interface *oi, struct ip *iph, struct ospf_header *ospfh)
+{
+       struct keychain *keychain = NULL;
+       struct key *key = NULL;
+       int key_id = ospfh->u.crypt.key_id;
+       uint8_t auth_data_len = ospfh->u.crypt.auth_data_len;
+
+       if (!OSPF_IF_PARAM(oi, keychain_name))
+               return ospf_auth_check_md5_digest(oi, ospfh, iph, NULL);
+
+       keychain = keychain_lookup(OSPF_IF_PARAM(oi, keychain_name));
+       if (!keychain) {
+               if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+                       flog_warn(EC_OSPF_AUTH,
+                                 "interface %s: Keychain %s is not available, Router-ID %pI4",
+                                 IF_NAME(oi), OSPF_IF_PARAM(oi, keychain_name),
+                                 &ospfh->router_id);
+               return 0;
+       }
+
+       key = key_lookup_for_accept(keychain, key_id);
+       if (!key) {
+               if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+                       flog_warn(EC_OSPF_AUTH,
+                                 "interface %s: Key ID %d not found in keychain %s, Router-ID %pI4",
+                                 IF_NAME(oi), key_id, keychain->name,
+                                 &ospfh->router_id);
+               return 0;
+       }
+
+       if (key->string == NULL || key->hash_algo == KEYCHAIN_ALGO_NULL) {
+               if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+                       flog_warn(EC_OSPF_AUTH,
+                                 "interface %s: Key ID %d in keychain %s is incomplete, Router-ID %pI4",
+                                 IF_NAME(oi), key_id, keychain->name,
+                                 &ospfh->router_id);
+               return 0;
+       }
+
+       if (keychain_get_hash_len(key->hash_algo) != auth_data_len) {
+               if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+                       flog_warn(EC_OSPF_AUTH,
+                                 "interface %s: Key ID %d in keychain %s hash length mismatch, Router-ID %pI4",
+                                 IF_NAME(oi), key_id, keychain->name,
+                                 &ospfh->router_id);
+               return 0;
+       }
+
+       /* Backward compatibility with RFC 2328 keyed-MD5 authentication */
+       if (key->hash_algo == KEYCHAIN_ALGO_MD5)
+               return ospf_auth_check_md5_digest(oi, ospfh, iph, key);
+
+       return ospf_auth_check_hmac_sha_digest(oi, ospfh, iph, key);
+}
+
+int ospf_auth_make_digest(struct ospf_interface *oi, struct ospf_packet *op)
+{
+       struct ospf_header *ospfh;
+       void *ibuf;
+       struct keychain *keychain = NULL;
+       struct key *key = NULL;
+       int key_id;
+
+       ibuf = STREAM_DATA(op->s);
+       ospfh = (struct ospf_header *)ibuf;
+
+       key_id = ospfh->u.crypt.key_id;
+
+       if (!OSPF_IF_PARAM(oi, keychain_name)) {
+               if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+                       flog_warn(EC_OSPF_AUTH,
+                                 "interface %s: Keychain is not set, Router-ID %pI4",
+                                 IF_NAME(oi), &ospfh->router_id);
+               return 0;
+       }
+
+       keychain = oi->keychain;
+       if (!keychain) {
+               if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, SEND))
+                       flog_warn(EC_OSPF_AUTH,
+                                 "interface %s: Keychain %s is not available to send, Router-ID %pI4",
+                                 IF_NAME(oi), OSPF_IF_PARAM(oi, keychain_name),
+                                 &ospfh->router_id);
+               return 0;
+       }
+
+       key = oi->key;
+       if (!key) {
+               if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, SEND))
+                       flog_warn(EC_OSPF_AUTH,
+                                 "interface %s: Key ID %d not found in keychain %s, Router-ID %pI4",
+                                 IF_NAME(oi), key_id, keychain->name,
+                                 &ospfh->router_id);
+               return 0;
+       }
+
+       if (key->string == NULL || key->hash_algo == KEYCHAIN_ALGO_NULL) {
+               if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, SEND))
+                       flog_warn(EC_OSPF_AUTH,
+                                 "interface %s: Key ID %d in keychain %s is incomplete, Router-ID %pI4",
+                                 IF_NAME(oi), key_id, keychain->name,
+                                 &ospfh->router_id);
+               return 0;
+       }
+
+       /* Backward compatibility with RFC 2328 keyed-MD5 authentication */
+       if (key->hash_algo == KEYCHAIN_ALGO_MD5)
+               return ospf_auth_make_md5_digest(oi, op, key);
+       else
+               return ospf_auth_make_hmac_sha_digest(oi, op, key);
+}
+
+/* This function is called from ospf_write(), it will detect the
+ * authentication scheme and if it is MD5, it will change the sequence
+ * and update the MD5 digest.
+ */
+
+int ospf_auth_make(struct ospf_interface *oi, struct ospf_packet *op)
+{
+       struct ospf_header *ospfh;
+       unsigned char digest[OSPF_AUTH_MD5_SIZE] = {0};
+#ifdef CRYPTO_OPENSSL
+       EVP_MD_CTX *ctx;
+#elif CRYPTO_INTERNAL
+       MD5_CTX ctx;
+#endif
+       void *ibuf;
+       uint32_t t;
+       struct crypt_key *ck;
+       const uint8_t *auth_key = NULL;
+
+       ibuf = STREAM_DATA(op->s);
+       ospfh = (struct ospf_header *)ibuf;
+
+       if (ntohs(ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC)
+               return 0;
+
+       /* We do this here so when we dup a packet, we don't have to
+        * waste CPU rewriting other headers.
+
+          Note that frr_time /deliberately/ is not used here.
+       */
+       t = (time(NULL) & 0xFFFFFFFF);
+       if (t > oi->crypt_seqnum)
+               oi->crypt_seqnum = t;
+       else
+               oi->crypt_seqnum++;
+
+       ospfh->u.crypt.crypt_seqnum = htonl(oi->crypt_seqnum);
+
+       /* Get MD5 Authentication key from auth_key list. */
+       if (list_isempty(OSPF_IF_PARAM(oi, auth_crypt)) && OSPF_IF_PARAM(oi, keychain_name) == NULL)
+               auth_key = (const uint8_t *)digest;
+       else if (!list_isempty(OSPF_IF_PARAM(oi, auth_crypt))) {
+               ck = listgetdata(listtail(OSPF_IF_PARAM(oi, auth_crypt)));
+               auth_key = ck->auth_key;
+       }
+
+       if (auth_key) {
+               /* Generate a digest for the entire packet + our secret key. */
+#ifdef CRYPTO_OPENSSL
+               unsigned int md5_size = OSPF_AUTH_MD5_SIZE;
+
+               ctx = EVP_MD_CTX_new();
+               EVP_DigestInit(ctx, EVP_md5());
+               EVP_DigestUpdate(ctx, ibuf, ntohs(ospfh->length));
+               EVP_DigestUpdate(ctx, auth_key, OSPF_AUTH_MD5_SIZE);
+               EVP_DigestFinal(ctx, digest, &md5_size);
+               EVP_MD_CTX_free(ctx);
+#elif CRYPTO_INTERNAL
+               memset(&ctx, 0, sizeof(ctx));
+               MD5Init(&ctx);
+               MD5Update(&ctx, ibuf, ntohs(ospfh->length));
+               MD5Update(&ctx, auth_key, OSPF_AUTH_MD5_SIZE);
+               MD5Final(digest, &ctx);
+#endif
+
+               /* Append md5 digest to the end of the stream. */
+               stream_put(op->s, digest, OSPF_AUTH_MD5_SIZE);
+
+               /* We do *NOT* increment the OSPF header length. */
+               op->length = ntohs(ospfh->length) + OSPF_AUTH_MD5_SIZE;
+
+               if (stream_get_endp(op->s) != op->length)
+                       /* XXX size_t */
+                       flog_warn(
+                               EC_OSPF_AUTH,
+                               "%s: length mismatch stream %lu ospf_packet %u, Router-ID %pI4",
+                               __func__, (unsigned long)stream_get_endp(op->s),
+                               op->length, &ospfh->router_id);
+
+               return OSPF_AUTH_MD5_SIZE;
+       } else
+               return ospf_auth_make_digest(oi, op);
+}
+
+/* Return 1, if the packet is properly authenticated and checksummed,
+ * 0 otherwise. In particular, check that AuType header field is valid and
+ * matches the locally configured AuType, and that D.5 requirements are met.
+ */
+int ospf_auth_check(struct ospf_interface *oi, struct ip *iph,
+                       struct ospf_header *ospfh)
+{
+       uint16_t iface_auth_type;
+       uint16_t pkt_auth_type = ntohs(ospfh->auth_type);
+
+       iface_auth_type = ospf_auth_type(oi);
+
+       switch (pkt_auth_type) {
+       case OSPF_AUTH_NULL: /* RFC2328 D.5.1 */
+               if (iface_auth_type != OSPF_AUTH_NULL) {
+                       if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+                               flog_warn(
+                                       EC_OSPF_PACKET,
+                                       "interface %s: auth-type mismatch, local %s, rcvd Null, Router-ID %pI4",
+                                       IF_NAME(oi),
+                                       lookup_msg(ospf_auth_type_str,
+                                                  iface_auth_type, NULL),
+                                       &ospfh->router_id);
+                       return 0;
+               }
+               if (!ospf_check_sum(ospfh)) {
+                       if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+                               flog_warn(
+                                       EC_OSPF_PACKET,
+                                       "interface %s: Null auth OK, but checksum error, Router-ID %pI4",
+                                       IF_NAME(oi),
+                                       &ospfh->router_id);
+                       return 0;
+               }
+               return 1;
+       case OSPF_AUTH_SIMPLE: /* RFC2328 D.5.2 */
+               if (iface_auth_type != OSPF_AUTH_SIMPLE) {
+                       if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+                               flog_warn(
+                                       EC_OSPF_PACKET,
+                                       "interface %s: auth-type mismatch, local %s, rcvd Simple, Router-ID %pI4",
+                                       IF_NAME(oi),
+                                       lookup_msg(ospf_auth_type_str,
+                                                  iface_auth_type, NULL),
+                                       &ospfh->router_id);
+                       return 0;
+               }
+               if (memcmp(OSPF_IF_PARAM(oi, auth_simple), ospfh->u.auth_data,
+                          OSPF_AUTH_SIMPLE_SIZE)) {
+                       if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+                               flog_warn(
+                                       EC_OSPF_PACKET,
+                                       "interface %s: Simple auth failed, Router-ID %pI4",
+                                       IF_NAME(oi), &ospfh->router_id);
+                       return 0;
+               }
+               if (!ospf_check_sum(ospfh)) {
+                       if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+                               flog_warn(
+                                       EC_OSPF_PACKET,
+                                       "interface %s: Simple auth OK, checksum error, Router-ID %pI4",
+                                       IF_NAME(oi),
+                                       &ospfh->router_id);
+                       return 0;
+               }
+               return 1;
+       case OSPF_AUTH_CRYPTOGRAPHIC: /* RFC2328 D.5.3 */
+               if (iface_auth_type != OSPF_AUTH_CRYPTOGRAPHIC) {
+                       if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+                               flog_warn(
+                                       EC_OSPF_PACKET,
+                                       "interface %s: auth-type mismatch, local %s, rcvd Cryptographic, Router-ID %pI4",
+                                       IF_NAME(oi),
+                                       lookup_msg(ospf_auth_type_str,
+                                                  iface_auth_type, NULL),
+                                       &ospfh->router_id);
+                       return 0;
+               }
+               if (ospfh->checksum) {
+                       if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+                               flog_warn(
+                                       EC_OSPF_PACKET,
+                                       "interface %s: OSPF header checksum is not 0, Router-ID %pI4",
+                                       IF_NAME(oi), &ospfh->router_id);
+                       return 0;
+               }
+               /* If `authentication message-digest` key is not set, we try keychain crypto */
+               if (OSPF_IF_PARAM(oi, keychain_name) || !list_isempty(OSPF_IF_PARAM(oi, auth_crypt)))
+                       return ospf_auth_check_digest(oi, iph, ospfh);
+               if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+                       flog_warn(
+                               EC_OSPF_AUTH,
+                               "interface %s: MD5 auth failed, Router-ID %pI4",
+                               IF_NAME(oi), &ospfh->router_id);
+               return 0;
+       default:
+               if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+                       flog_warn(
+                               EC_OSPF_PACKET,
+                               "interface %s: invalid packet auth-type (%02x), Router-ID %pI4",
+                               IF_NAME(oi), pkt_auth_type, &ospfh->router_id);
+               return 0;
+       }
+}
+
+/* OSPF authentication checking function */
+int ospf_auth_type(struct ospf_interface *oi)
+{
+       int auth_type;
+
+       if (OSPF_IF_PARAM(oi, auth_type) == OSPF_AUTH_NOTSET)
+               auth_type = oi->area->auth_type;
+       else
+               auth_type = OSPF_IF_PARAM(oi, auth_type);
+
+       /* Handle case where MD5 key list, or a key-chain, is not configured aka Cisco */
+       if (auth_type == OSPF_AUTH_CRYPTOGRAPHIC
+           && (list_isempty(OSPF_IF_PARAM(oi, auth_crypt))
+               && OSPF_IF_PARAM(oi, keychain_name) == NULL))
+               return OSPF_AUTH_NULL;
+
+       return auth_type;
+}
+
+/* Make Authentication Data. */
+int ospf_auth_make_data(struct ospf_interface *oi, struct ospf_header *ospfh)
+{
+       struct crypt_key *ck;
+
+       switch (ospf_auth_type(oi)) {
+       case OSPF_AUTH_NULL:
+               /* memset (ospfh->u.auth_data, 0, sizeof(ospfh->u.auth_data));
+                */
+               break;
+       case OSPF_AUTH_SIMPLE:
+               memcpy(ospfh->u.auth_data, OSPF_IF_PARAM(oi, auth_simple),
+                      OSPF_AUTH_SIMPLE_SIZE);
+               break;
+       case OSPF_AUTH_CRYPTOGRAPHIC:
+               if (OSPF_IF_PARAM(oi, keychain_name)) {
+                       oi->keychain = keychain_lookup(OSPF_IF_PARAM(oi, keychain_name));
+                       if (oi->keychain)
+                               oi->key = key_lookup_for_send(oi->keychain);
+                       if (oi->key) {
+                               ospfh->u.crypt.zero = 0;
+                               ospfh->u.crypt.key_id = oi->key->index;
+                               ospfh->u.crypt.auth_data_len = keychain_get_hash_len(oi->key->hash_algo);
+                       } else {
+                               /* If key is not set, then set 0. */
+                               ospfh->u.crypt.zero = 0;
+                               ospfh->u.crypt.key_id = 0;
+                               ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE;
+                       }
+               } else {
+                       /* If key is not set, then set 0. */
+                       if (list_isempty(OSPF_IF_PARAM(oi, auth_crypt))) {
+                               ospfh->u.crypt.zero = 0;
+                               ospfh->u.crypt.key_id = 0;
+                               ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE;
+                       } else {
+                               ck = listgetdata(
+                                       listtail(OSPF_IF_PARAM(oi, auth_crypt)));
+                               ospfh->u.crypt.zero = 0;
+                               ospfh->u.crypt.key_id = ck->key_id;
+                               ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE;
+                       }
+               }
+               /* note: the seq is done in ospf_auth_make() */
+               break;
+       default:
+               /* memset (ospfh->u.auth_data, 0, sizeof(ospfh->u.auth_data));
+                */
+               break;
+       }
+
+       return 0;
+}
diff --git a/ospfd/ospf_auth.h b/ospfd/ospf_auth.h
new file mode 100644 (file)
index 0000000..6f6d3db
--- /dev/null
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2023 Amnesh Inc.
+ *                    Mahdi Varasteh
+ */
+
+#ifndef _ZEBRA_OSPF_AUTH_H
+#define _ZEBRA_OSPF_AUTH_H
+
+#include <ospfd/ospf_gr.h>
+#include <ospfd/ospf_packet.h>
+
+int ospf_auth_check(struct ospf_interface *oi, struct ip *iph, struct ospf_header *ospfh);
+int ospf_auth_check_digest(struct ospf_interface *oi, struct ip *iph, struct ospf_header *ospfh);
+int ospf_auth_make(struct ospf_interface *oi, struct ospf_packet *op);
+int ospf_auth_make_digest(struct ospf_interface *oi, struct ospf_packet *op);
+int ospf_auth_type(struct ospf_interface *oi);
+int ospf_auth_make_data(struct ospf_interface *oi, struct ospf_header *ospfh);
+
+#endif /* _ZEBRA_OSPF_AUTH_H */
index 16aa3ab5267f9e378b1e5f527e01fce715910a66..cf58c6ad8b8d2338d2a305a43ce39c5317e28c37 100644 (file)
@@ -19,9 +19,9 @@ static struct log_ref ferr_ospf_warn[] = {
                .suggestion = "Do not use this particular set command for an ospf route-map",
        },
        {
-               .code = EC_OSPF_MD5,
-               .title = "OSPF has noticed a MD5 issue",
-               .description = "Something has gone wrong with the calculation of the MD5 data",
+               .code = EC_OSPF_AUTH,
+               .title = "OSPF has noticed an authentication issue",
+               .description = "Something has gone wrong with the calculation of the authentication data",
                .suggestion = "Ensure your key is correct, gather log data from this side as well as peer and open an Issue",
        },
        {
index dcf9a65ce939b08545280a32448f1ec4c3335c4c..e63cb7409cb559c819a34506aabeeb28949e8efd 100644 (file)
@@ -22,7 +22,7 @@ enum ospf_log_refs {
        EC_OSPF_INVALID_ALGORITHM,
        EC_OSPF_FSM_INVALID_STATE,
        EC_OSPF_SET_METRIC_PLUS,
-       EC_OSPF_MD5,
+       EC_OSPF_AUTH,
        EC_OSPF_PACKET,
        EC_OSPF_LARGE_LSA,
        EC_OSPF_LSA_UNEXPECTED,
index bdab672b475fad129925c775eb0b9b7e19c62cda..7601419325d5da1c1b27bac75937e8978e7e3527 100644 (file)
@@ -549,6 +549,7 @@ static struct ospf_if_params *ospf_new_if_params(void)
        UNSET_IF_PARAM(oip, auth_type);
        UNSET_IF_PARAM(oip, if_area);
        UNSET_IF_PARAM(oip, opaque_capable);
+       UNSET_IF_PARAM(oip, keychain_name);
 
        oip->auth_crypt = list_new();
 
@@ -566,6 +567,7 @@ static void ospf_del_if_params(struct interface *ifp,
                               struct ospf_if_params *oip)
 {
        list_delete(&oip->auth_crypt);
+       XFREE(MTYPE_OSPF_IF_PARAMS, oip->keychain_name);
        ospf_interface_disable_bfd(ifp, oip);
        ldp_sync_info_free(&(oip->ldp_sync_info));
        XFREE(MTYPE_OSPF_IF_PARAMS, oip);
@@ -601,6 +603,7 @@ void ospf_free_if_params(struct interface *ifp, struct in_addr addr)
            !OSPF_IF_PARAM_CONFIGURED(oip, if_area) &&
            !OSPF_IF_PARAM_CONFIGURED(oip, opaque_capable) &&
            !OSPF_IF_PARAM_CONFIGURED(oip, prefix_suppression) &&
+               !OSPF_IF_PARAM_CONFIGURED(oip, keychain_name) &&
            listcount(oip->auth_crypt) == 0) {
                ospf_del_if_params(ifp, oip);
                rn->info = NULL;
index 47b70f8039403ee4824691778f5f7c3fa7f9f807..e2290a881cc410b3ecc432f4bb84f1c68551e683 100644 (file)
@@ -10,6 +10,7 @@
 #include "lib/bfd.h"
 #include "qobj.h"
 #include "hook.h"
+#include "keychain.h"
 #include "ospfd/ospf_packet.h"
 #include "ospfd/ospf_spf.h"
 
@@ -92,6 +93,8 @@ struct ospf_if_params {
                         auth_crypt);     /* List of Auth cryptographic data. */
        DECLARE_IF_PARAM(int, auth_type); /* OSPF authentication type */
 
+       DECLARE_IF_PARAM(char*, keychain_name); /* OSPF HMAC Cryptographic Authentication*/
+
        /* Other, non-configuration state */
        uint32_t network_lsa_seqnum; /* Network LSA seqnum */
 
@@ -279,6 +282,10 @@ struct ospf_interface {
 
        uint32_t full_nbrs;
 
+       /* Buffered values for keychain and key */
+       struct keychain *keychain;
+       struct key *key;
+
        QOBJ_FIELDS;
 };
 DECLARE_QOBJ_TYPE(ospf_interface);
index 536bd592d238b8a85f5765533de35bba151c5916..dd000241f4035714fa9c886c63fb91c6baff04a4 100644 (file)
@@ -27,6 +27,7 @@
 #include "vrf.h"
 #include "libfrr.h"
 #include "routemap.h"
+#include "keychain.h"
 
 #include "ospfd/ospfd.h"
 #include "ospfd/ospf_interface.h"
@@ -218,6 +219,7 @@ int main(int argc, char **argv)
 
        access_list_init();
        prefix_list_init();
+       keychain_init();
 
        /* Configuration processing callback initialization. */
        cmd_init_config_callbacks(ospf_config_start, ospf_config_end);
index cfa0d5d574442bb592a8fcdd7875b6a1a570311f..b37efa3efa21fc72d461a609fa2f86139f945958 100644 (file)
@@ -41,6 +41,7 @@
 #include "ospfd/ospf_errors.h"
 #include "ospfd/ospf_zebra.h"
 #include "ospfd/ospf_gr.h"
+#include "ospfd/ospf_auth.h"
 
 /*
  * OSPF Fragmentation / fragmented writes
@@ -99,27 +100,6 @@ static const uint16_t ospf_lsa_minlen[] = {
        OSPF_OPAQUE_LSA_MIN_SIZE,      /* OSPF_OPAQUE_AS_LSA */
 };
 
-/* for ospf_check_auth() */
-static int ospf_check_sum(struct ospf_header *);
-
-/* OSPF authentication checking function */
-static int ospf_auth_type(struct ospf_interface *oi)
-{
-       int auth_type;
-
-       if (OSPF_IF_PARAM(oi, auth_type) == OSPF_AUTH_NOTSET)
-               auth_type = oi->area->auth_type;
-       else
-               auth_type = OSPF_IF_PARAM(oi, auth_type);
-
-       /* Handle case where MD5 key list is not configured aka Cisco */
-       if (auth_type == OSPF_AUTH_CRYPTOGRAPHIC
-           && list_isempty(OSPF_IF_PARAM(oi, auth_crypt)))
-               return OSPF_AUTH_NULL;
-
-       return auth_type;
-}
-
 static struct ospf_packet *ospf_packet_new(size_t size)
 {
        struct ospf_packet *new;
@@ -258,8 +238,8 @@ static struct ospf_packet *ospf_packet_dup(struct ospf_packet *op)
                        "ospf_packet_dup stream %lu ospf_packet %u size mismatch",
                        (unsigned long)STREAM_SIZE(op->s), op->length);
 
-       /* Reserve space for MD5 authentication that may be added later. */
-       new = ospf_packet_new(stream_get_endp(op->s) + OSPF_AUTH_MD5_SIZE);
+       /* Reserve space for MD5/HMAC SHA authentication that may be added later. */
+       new = ospf_packet_new(stream_get_endp(op->s) + KEYCHAIN_MAX_HASH_SIZE);
        stream_copy(new->s, op->s);
 
        new->dst = op->dst;
@@ -274,7 +254,7 @@ static unsigned int ospf_packet_authspace(struct ospf_interface *oi)
        int auth = 0;
 
        if (ospf_auth_type(oi) == OSPF_AUTH_CRYPTOGRAPHIC)
-               auth = OSPF_AUTH_MD5_SIZE;
+               auth = KEYCHAIN_MAX_HASH_SIZE;
 
        return auth;
 }
@@ -290,155 +270,6 @@ static unsigned int ospf_packet_max(struct ospf_interface *oi)
        return max;
 }
 
-
-static int ospf_check_md5_digest(struct ospf_interface *oi,
-                                struct ospf_header *ospfh)
-{
-#ifdef CRYPTO_OPENSSL
-       EVP_MD_CTX *ctx;
-#elif CRYPTO_INTERNAL
-       MD5_CTX ctx;
-#endif
-       unsigned char digest[OSPF_AUTH_MD5_SIZE];
-       struct crypt_key *ck;
-       struct ospf_neighbor *nbr;
-       uint16_t length = ntohs(ospfh->length);
-
-       /* Get secret key. */
-       ck = ospf_crypt_key_lookup(OSPF_IF_PARAM(oi, auth_crypt),
-                                  ospfh->u.crypt.key_id);
-       if (ck == NULL) {
-               flog_warn(
-                       EC_OSPF_MD5,
-                       "interface %s: ospf_check_md5 no key %d, Router-ID: %pI4",
-                       IF_NAME(oi), ospfh->u.crypt.key_id, &ospfh->router_id);
-               return 0;
-       }
-
-       /* check crypto seqnum. */
-       nbr = ospf_nbr_lookup_by_routerid(oi->nbrs, &ospfh->router_id);
-
-       if (nbr
-           && ntohl(nbr->crypt_seqnum) > ntohl(ospfh->u.crypt.crypt_seqnum)) {
-               flog_warn(
-                       EC_OSPF_MD5,
-                       "interface %s: ospf_check_md5 bad sequence %d (expect %d), Router-ID: %pI4",
-                       IF_NAME(oi), ntohl(ospfh->u.crypt.crypt_seqnum),
-                       ntohl(nbr->crypt_seqnum), &ospfh->router_id);
-               return 0;
-       }
-
-       /* Generate a digest for the ospf packet - their digest + our digest. */
-#ifdef CRYPTO_OPENSSL
-       unsigned int md5_size = OSPF_AUTH_MD5_SIZE;
-       ctx = EVP_MD_CTX_new();
-       EVP_DigestInit(ctx, EVP_md5());
-       EVP_DigestUpdate(ctx, ospfh, length);
-       EVP_DigestUpdate(ctx, ck->auth_key, OSPF_AUTH_MD5_SIZE);
-       EVP_DigestFinal(ctx, digest, &md5_size);
-       EVP_MD_CTX_free(ctx);
-#elif CRYPTO_INTERNAL
-       memset(&ctx, 0, sizeof(ctx));
-       MD5Init(&ctx);
-       MD5Update(&ctx, ospfh, length);
-       MD5Update(&ctx, ck->auth_key, OSPF_AUTH_MD5_SIZE);
-       MD5Final(digest, &ctx);
-#endif
-
-       /* compare the two */
-       if (memcmp((caddr_t)ospfh + length, digest, OSPF_AUTH_MD5_SIZE)) {
-               flog_warn(
-                       EC_OSPF_MD5,
-                       "interface %s: ospf_check_md5 checksum mismatch, Router-ID: %pI4",
-                       IF_NAME(oi), &ospfh->router_id);
-               return 0;
-       }
-
-       /* save neighbor's crypt_seqnum */
-       if (nbr)
-               nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum;
-       return 1;
-}
-
-/* This function is called from ospf_write(), it will detect the
-   authentication scheme and if it is MD5, it will change the sequence
-   and update the MD5 digest. */
-static int ospf_make_md5_digest(struct ospf_interface *oi,
-                               struct ospf_packet *op)
-{
-       struct ospf_header *ospfh;
-       unsigned char digest[OSPF_AUTH_MD5_SIZE] = {0};
-#ifdef CRYPTO_OPENSSL
-       EVP_MD_CTX *ctx;
-#elif CRYPTO_INTERNAL
-       MD5_CTX ctx;
-#endif
-       void *ibuf;
-       uint32_t t;
-       struct crypt_key *ck;
-       const uint8_t *auth_key;
-
-       ibuf = STREAM_DATA(op->s);
-       ospfh = (struct ospf_header *)ibuf;
-
-       if (ntohs(ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC)
-               return 0;
-
-       /* We do this here so when we dup a packet, we don't have to
-          waste CPU rewriting other headers.
-
-          Note that frr_time /deliberately/ is not used here */
-       t = (time(NULL) & 0xFFFFFFFF);
-       if (t > oi->crypt_seqnum)
-               oi->crypt_seqnum = t;
-       else
-               oi->crypt_seqnum++;
-
-       ospfh->u.crypt.crypt_seqnum = htonl(oi->crypt_seqnum);
-
-       /* Get MD5 Authentication key from auth_key list. */
-       if (list_isempty(OSPF_IF_PARAM(oi, auth_crypt)))
-               auth_key = (const uint8_t *)digest;
-       else {
-               ck = listgetdata(listtail(OSPF_IF_PARAM(oi, auth_crypt)));
-               auth_key = ck->auth_key;
-       }
-
-       /* Generate a digest for the entire packet + our secret key. */
-#ifdef CRYPTO_OPENSSL
-       unsigned int md5_size = OSPF_AUTH_MD5_SIZE;
-       ctx = EVP_MD_CTX_new();
-       EVP_DigestInit(ctx, EVP_md5());
-       EVP_DigestUpdate(ctx, ibuf, ntohs(ospfh->length));
-       EVP_DigestUpdate(ctx, auth_key, OSPF_AUTH_MD5_SIZE);
-       EVP_DigestFinal(ctx, digest, &md5_size);
-       EVP_MD_CTX_free(ctx);
-#elif CRYPTO_INTERNAL
-       memset(&ctx, 0, sizeof(ctx));
-       MD5Init(&ctx);
-       MD5Update(&ctx, ibuf, ntohs(ospfh->length));
-       MD5Update(&ctx, auth_key, OSPF_AUTH_MD5_SIZE);
-       MD5Final(digest, &ctx);
-#endif
-
-       /* Append md5 digest to the end of the stream. */
-       stream_put(op->s, digest, OSPF_AUTH_MD5_SIZE);
-
-       /* We do *NOT* increment the OSPF header length. */
-       op->length = ntohs(ospfh->length) + OSPF_AUTH_MD5_SIZE;
-
-       if (stream_get_endp(op->s) != op->length)
-               /* XXX size_t */
-               flog_warn(
-                       EC_OSPF_MD5,
-                       "%s: length mismatch stream %lu ospf_packet %u, Router-ID %pI4",
-                       __func__, (unsigned long)stream_get_endp(op->s),
-                       op->length, &ospfh->router_id);
-
-       return OSPF_AUTH_MD5_SIZE;
-}
-
-
 static void ospf_ls_req_timer(struct event *thread)
 {
        struct ospf_neighbor *nbr;
@@ -677,7 +508,7 @@ static void ospf_write(struct event *thread)
                        ospf_if_ipmulticast(fd, oi->address, oi->ifp->ifindex);
 
                /* Rewrite the md5 signature & update the seq */
-               ospf_make_md5_digest(oi, op);
+               ospf_auth_make(oi, op);
 
                /* Retrieve OSPF packet type. */
                stream_set_getp(op->s, 1);
@@ -2476,142 +2307,6 @@ static int ospf_check_network_mask(struct ospf_interface *oi,
        return 0;
 }
 
-/* Return 1, if the packet is properly authenticated and checksummed,
-   0 otherwise. In particular, check that AuType header field is valid and
-   matches the locally configured AuType, and that D.5 requirements are met. */
-static int ospf_check_auth(struct ospf_interface *oi, struct ospf_header *ospfh)
-{
-       struct crypt_key *ck;
-       uint16_t iface_auth_type;
-       uint16_t pkt_auth_type = ntohs(ospfh->auth_type);
-
-       switch (pkt_auth_type) {
-       case OSPF_AUTH_NULL: /* RFC2328 D.5.1 */
-               if (OSPF_AUTH_NULL != (iface_auth_type = ospf_auth_type(oi))) {
-                       if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
-                               flog_warn(
-                                       EC_OSPF_PACKET,
-                                       "interface %s: auth-type mismatch, local %s, rcvd Null, Router-ID %pI4",
-                                       IF_NAME(oi),
-                                       lookup_msg(ospf_auth_type_str,
-                                                  iface_auth_type, NULL),
-                                       &ospfh->router_id);
-                       return 0;
-               }
-               if (!ospf_check_sum(ospfh)) {
-                       if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
-                               flog_warn(
-                                       EC_OSPF_PACKET,
-                                       "interface %s: Null auth OK, but checksum error, Router-ID %pI4",
-                                       IF_NAME(oi),
-                                       &ospfh->router_id);
-                       return 0;
-               }
-               return 1;
-       case OSPF_AUTH_SIMPLE: /* RFC2328 D.5.2 */
-               if (OSPF_AUTH_SIMPLE
-                   != (iface_auth_type = ospf_auth_type(oi))) {
-                       if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
-                               flog_warn(
-                                       EC_OSPF_PACKET,
-                                       "interface %s: auth-type mismatch, local %s, rcvd Simple, Router-ID %pI4",
-                                       IF_NAME(oi),
-                                       lookup_msg(ospf_auth_type_str,
-                                                  iface_auth_type, NULL),
-                                       &ospfh->router_id);
-                       return 0;
-               }
-               if (memcmp(OSPF_IF_PARAM(oi, auth_simple), ospfh->u.auth_data,
-                          OSPF_AUTH_SIMPLE_SIZE)) {
-                       if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
-                               flog_warn(
-                                       EC_OSPF_PACKET,
-                                       "interface %s: Simple auth failed, Router-ID %pI4",
-                                       IF_NAME(oi), &ospfh->router_id);
-                       return 0;
-               }
-               if (!ospf_check_sum(ospfh)) {
-                       if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
-                               flog_warn(
-                                       EC_OSPF_PACKET,
-                                       "interface %s: Simple auth OK, checksum error, Router-ID %pI4",
-                                       IF_NAME(oi),
-                                       &ospfh->router_id);
-                       return 0;
-               }
-               return 1;
-       case OSPF_AUTH_CRYPTOGRAPHIC: /* RFC2328 D.5.3 */
-               if (OSPF_AUTH_CRYPTOGRAPHIC
-                   != (iface_auth_type = ospf_auth_type(oi))) {
-                       if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
-                               flog_warn(
-                                       EC_OSPF_PACKET,
-                                       "interface %s: auth-type mismatch, local %s, rcvd Cryptographic, Router-ID %pI4",
-                                       IF_NAME(oi),
-                                       lookup_msg(ospf_auth_type_str,
-                                                  iface_auth_type, NULL),
-                                       &ospfh->router_id);
-                       return 0;
-               }
-               if (ospfh->checksum) {
-                       if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
-                               flog_warn(
-                                       EC_OSPF_PACKET,
-                                       "interface %s: OSPF header checksum is not 0, Router-ID %pI4",
-                                       IF_NAME(oi), &ospfh->router_id);
-                       return 0;
-               }
-               /* only MD5 crypto method can pass ospf_packet_examin() */
-               if (NULL == (ck = listgetdata(
-                                    listtail(OSPF_IF_PARAM(oi, auth_crypt))))
-                   || ospfh->u.crypt.key_id != ck->key_id ||
-                   /* Condition above uses the last key ID on the list,
-                      which is
-                      different from what ospf_crypt_key_lookup() does. A
-                      bug? */
-                   !ospf_check_md5_digest(oi, ospfh)) {
-                       if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
-                               flog_warn(
-                                       EC_OSPF_MD5,
-                                       "interface %s: MD5 auth failed, Router-ID %pI4",
-                                       IF_NAME(oi), &ospfh->router_id);
-                       return 0;
-               }
-               return 1;
-       default:
-               if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
-                       flog_warn(
-                               EC_OSPF_PACKET,
-                               "interface %s: invalid packet auth-type (%02x), Router-ID %pI4",
-                               IF_NAME(oi), pkt_auth_type, &ospfh->router_id);
-               return 0;
-       }
-}
-
-static int ospf_check_sum(struct ospf_header *ospfh)
-{
-       uint32_t ret;
-       uint16_t sum;
-
-       /* clear auth_data for checksum. */
-       memset(ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE);
-
-       /* keep checksum and clear. */
-       sum = ospfh->checksum;
-       memset(&ospfh->checksum, 0, sizeof(uint16_t));
-
-       /* calculate checksum. */
-       ret = in_cksum(ospfh, ntohs(ospfh->length));
-
-       if (ret != sum) {
-               zlog_info("%s: checksum mismatch, my %X, his %X", __func__, ret,
-                         sum);
-               return 0;
-       }
-
-       return 1;
-}
-
 /* Verify, that given link/TOS records are properly sized/aligned and match
    Router-LSA "# links" and "# TOS" fields as specified in RFC2328 A.4.2. */
 static unsigned ospf_router_lsa_links_examin(struct router_lsa_link *link,
@@ -2835,14 +2530,14 @@ static unsigned ospf_packet_examin(struct ospf_header *oh,
        if (ntohs(oh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC)
                bytesauth = 0;
        else {
-               if (oh->u.crypt.auth_data_len != OSPF_AUTH_MD5_SIZE) {
+               if (oh->u.crypt.auth_data_len > KEYCHAIN_MAX_HASH_SIZE) {
                        if (IS_DEBUG_OSPF_PACKET(0, RECV))
                                zlog_debug(
                                        "%s: unsupported crypto auth length (%u B)",
                                        __func__, oh->u.crypt.auth_data_len);
                        return MSG_NG;
                }
-               bytesauth = OSPF_AUTH_MD5_SIZE;
+               bytesauth = oh->u.crypt.auth_data_len;
        }
        if (bytesdeclared + bytesauth > bytesonwire) {
                if (IS_DEBUG_OSPF_PACKET(0, RECV))
@@ -2953,7 +2648,7 @@ static int ospf_verify_header(struct stream *ibuf, struct ospf_interface *oi,
 
        /* Check authentication. The function handles logging actions, where
         * required. */
-       if (!ospf_check_auth(oi, ospfh))
+       if (!ospf_auth_check(oi, iph, ospfh))
                return -1;
 
        return 0;
@@ -3261,44 +2956,6 @@ static void ospf_make_header(int type, struct ospf_interface *oi,
        stream_forward_endp(s, OSPF_HEADER_SIZE);
 }
 
-/* Make Authentication Data. */
-static int ospf_make_auth(struct ospf_interface *oi, struct ospf_header *ospfh)
-{
-       struct crypt_key *ck;
-
-       switch (ospf_auth_type(oi)) {
-       case OSPF_AUTH_NULL:
-               /* memset (ospfh->u.auth_data, 0, sizeof(ospfh->u.auth_data));
-                */
-               break;
-       case OSPF_AUTH_SIMPLE:
-               memcpy(ospfh->u.auth_data, OSPF_IF_PARAM(oi, auth_simple),
-                      OSPF_AUTH_SIMPLE_SIZE);
-               break;
-       case OSPF_AUTH_CRYPTOGRAPHIC:
-               /* If key is not set, then set 0. */
-               if (list_isempty(OSPF_IF_PARAM(oi, auth_crypt))) {
-                       ospfh->u.crypt.zero = 0;
-                       ospfh->u.crypt.key_id = 0;
-                       ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE;
-               } else {
-                       ck = listgetdata(
-                               listtail(OSPF_IF_PARAM(oi, auth_crypt)));
-                       ospfh->u.crypt.zero = 0;
-                       ospfh->u.crypt.key_id = ck->key_id;
-                       ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE;
-               }
-               /* note: the seq is done in ospf_make_md5_digest() */
-               break;
-       default:
-               /* memset (ospfh->u.auth_data, 0, sizeof(ospfh->u.auth_data));
-                */
-               break;
-       }
-
-       return 0;
-}
-
 /* Fill rest of OSPF header. */
 static void ospf_fill_header(struct ospf_interface *oi, struct stream *s,
                             uint16_t length)
@@ -3317,7 +2974,9 @@ static void ospf_fill_header(struct ospf_interface *oi, struct stream *s,
                ospfh->checksum = 0;
 
        /* Add Authentication Data. */
-       ospf_make_auth(oi, ospfh);
+       oi->keychain = NULL;
+       oi->key = NULL;
+       ospf_auth_make_data(oi, ospfh);
 }
 
 static int ospf_make_hello(struct ospf_interface *oi, struct stream *s)
index 158e90df59d57c27e53bff7a5d41a94b2578c702..8c3ad7f372d5d63f60f28b5b97b53026a7f4bfc3 100644 (file)
@@ -21,6 +21,7 @@
 #include <lib/json.h>
 #include "defaults.h"
 #include "lib/printfrr.h"
+#include "keychain.h"
 
 #include "ospfd/ospfd.h"
 #include "ospfd/ospf_asbr.h"
@@ -40,6 +41,7 @@
 #include "ospfd/ospf_bfd.h"
 #include "ospfd/ospf_ldp_sync.h"
 #include "ospfd/ospf_network.h"
+#include "ospfd/ospf_memory.h"
 
 FRR_CFG_DEFAULT_BOOL(OSPF_LOG_ADJACENCY_CHANGES,
        { .val_bool = true, .match_profile = "datacenter", },
@@ -808,6 +810,8 @@ struct ospf_vl_config_data {
        char *auth_key;         /* simple password if present */
        int crypto_key_id;      /* Cryptographic key ID */
        char *md5_key;          /* MD5 authentication key */
+       char *keychain;     /* Cryptographic keychain */
+       int del_keychain;
        int hello_interval;     /* Obvious what these are... */
        int retransmit_interval;
        int transmit_delay;
@@ -890,6 +894,10 @@ static int ospf_vl_set_security(struct ospf_vl_data *vl_data,
                strlcpy((char *)IF_DEF_PARAMS(ifp)->auth_simple,
                        vl_config->auth_key,
                        sizeof(IF_DEF_PARAMS(ifp)->auth_simple));
+       } else if (vl_config->keychain) {
+               SET_IF_PARAM(IF_DEF_PARAMS(ifp), keychain_name);
+               XFREE(MTYPE_OSPF_IF_PARAMS, IF_DEF_PARAMS(ifp)->keychain_name);
+               IF_DEF_PARAMS(ifp)->keychain_name = XSTRDUP(MTYPE_OSPF_IF_PARAMS, vl_config->keychain);
        } else if (vl_config->md5_key) {
                if (ospf_crypt_key_lookup(IF_DEF_PARAMS(ifp)->auth_crypt,
                                          vl_config->crypto_key_id)
@@ -918,6 +926,9 @@ static int ospf_vl_set_security(struct ospf_vl_data *vl_data,
 
                ospf_crypt_key_delete(IF_DEF_PARAMS(ifp)->auth_crypt,
                                      vl_config->crypto_key_id);
+       } else if (vl_config->del_keychain) {
+               UNSET_IF_PARAM(IF_DEF_PARAMS(ifp), keychain_name);
+               XFREE(MTYPE_OSPF_IF_PARAMS, IF_DEF_PARAMS(ifp)->keychain_name);
        }
 
        return CMD_SUCCESS;
@@ -1022,9 +1033,11 @@ static int ospf_vl_set(struct ospf *ospf, struct ospf_vl_config_data *vl_config)
 
 DEFUN (ospf_area_vlink,
        ospf_area_vlink_cmd,
-       "area <A.B.C.D|(0-4294967295)> virtual-link A.B.C.D [authentication [<message-digest|null>]] [<message-digest-key (1-255) md5 KEY|authentication-key AUTH_KEY>]",
+       "area <A.B.C.D|(0-4294967295)> virtual-link A.B.C.D [authentication [<key-chain KEYCHAIN_NAME|message-digest|null>]] [<message-digest-key (1-255) md5 KEY|authentication-key AUTH_KEY>]",
        VLINK_HELPSTR_IPADDR
        "Enable authentication on this virtual link\n"
+          "Use a key-chain for cryptographic authentication keys\n"
+          "Key-chain name\n"
        "Use message-digest authentication\n"
        "Use null authentication\n"
        VLINK_HELPSTR_AUTH_MD5
@@ -1067,7 +1080,10 @@ DEFUN (ospf_area_vlink,
                vl_config.auth_type = OSPF_AUTH_SIMPLE;
        }
 
-       if (argv_find(argv, argc, "message-digest", &idx)) {
+       if (argv_find(argv, argc, "key-chain", &idx)) {
+               vl_config.auth_type = OSPF_AUTH_CRYPTOGRAPHIC;
+               vl_config.keychain = argv[idx+1]->arg;
+       } else if (argv_find(argv, argc, "message-digest", &idx)) {
                /* authentication message-digest */
                vl_config.auth_type = OSPF_AUTH_CRYPTOGRAPHIC;
        } else if (argv_find(argv, argc, "null", &idx)) {
@@ -1097,10 +1113,12 @@ DEFUN (ospf_area_vlink,
 
 DEFUN (no_ospf_area_vlink,
        no_ospf_area_vlink_cmd,
-       "no area <A.B.C.D|(0-4294967295)> virtual-link A.B.C.D [authentication [<message-digest|null>]] [<message-digest-key (1-255) md5 KEY|authentication-key AUTH_KEY>]",
+       "no area <A.B.C.D|(0-4294967295)> virtual-link A.B.C.D [authentication [<key-chain KEYCHAIN_NAME|message-digest|null>]] [<message-digest-key (1-255) md5 KEY|authentication-key AUTH_KEY>]",
        NO_STR
        VLINK_HELPSTR_IPADDR
        "Enable authentication on this virtual link\n"
+          "Use a key-chain for cryptographic authentication keys\n"
+          "Key-chain name\n"
        "Use message-digest authentication\n"
        "Use null authentication\n"
        VLINK_HELPSTR_AUTH_MD5
@@ -1160,6 +1178,11 @@ DEFUN (no_ospf_area_vlink,
                vl_config.auth_type = OSPF_AUTH_NOTSET;
        }
 
+       if (argv_find(argv, argc, "key-chain", &idx)) {
+               vl_config.del_keychain = 1;
+               vl_config.keychain = NULL;
+       }
+
        if (argv_find(argv, argc, "message-digest-key", &idx)) {
                vl_config.md5_key = NULL;
                vl_config.crypto_key_id = strtol(argv[idx + 1]->arg, NULL, 10);
@@ -3597,18 +3620,41 @@ static void ospf_interface_auth_show(struct vty *vty, struct ospf_interface *oi,
        case OSPF_AUTH_CRYPTOGRAPHIC: {
                struct crypt_key *ckey;
 
-               if (list_isempty(OSPF_IF_PARAM(oi, auth_crypt)))
-                       return;
-
-               ckey = listgetdata(listtail(OSPF_IF_PARAM(oi, auth_crypt)));
-               if (ckey) {
+               if (OSPF_IF_PARAM(oi, keychain_name)) {
                        if (use_json) {
                                json_object_string_add(json, "authentication",
-                                                      "authenticationMessageDigest");
+                                                         "authenticationKeyChain");
+                               json_object_string_add(json, "keychain",
+                                                         OSPF_IF_PARAM(oi, keychain_name));
                        } else {
                                vty_out(vty,
                                        "  Cryptographic authentication enabled\n");
-                               vty_out(vty, "  Algorithm:MD5\n");
+                               struct keychain *keychain = keychain_lookup(OSPF_IF_PARAM(oi, keychain_name));
+
+                               if (keychain) {
+                                       struct key *key = key_lookup_for_send(keychain);
+
+                                       if (key) {
+                                               vty_out(vty, "    Sending SA: Key %u, Algorithm %s - key chain %s\n",
+                                                               key->index, keychain_get_algo_name_by_id(key->hash_algo),
+                                                               OSPF_IF_PARAM(oi, keychain_name));
+                                       }
+                               }
+                       }
+               } else {
+                       if (list_isempty(OSPF_IF_PARAM(oi, auth_crypt)))
+                               return;
+
+                       ckey = listgetdata(listtail(OSPF_IF_PARAM(oi, auth_crypt)));
+                       if (ckey) {
+                               if (use_json) {
+                                       json_object_string_add(json, "authentication",
+                                                               "authenticationMessageDigest");
+                               } else {
+                                       vty_out(vty,
+                                               "  Cryptographic authentication enabled\n");
+                                       vty_out(vty, "  Algorithm:MD5\n");
+                               }
                        }
                }
                break;
@@ -7535,24 +7581,26 @@ DEFPY (show_ip_ospf_database,
 
 DEFUN (ip_ospf_authentication_args,
        ip_ospf_authentication_args_addr_cmd,
-       "ip ospf authentication <null|message-digest> [A.B.C.D]",
+       "ip ospf authentication <null|message-digest|key-chain KEYCHAIN_NAME> [A.B.C.D]",
        "IP Information\n"
        "OSPF interface commands\n"
        "Enable authentication on this interface\n"
        "Use null authentication\n"
        "Use message-digest authentication\n"
+          "Use a key-chain for cryptographic authentication keys\n"
+          "Key-chain name\n"
        "Address of interface\n")
 {
        VTY_DECLVAR_CONTEXT(interface, ifp);
        int idx_encryption = 3;
-       int idx_ipv4 = 4;
+       int idx_ipv4 = argc-1;
        struct in_addr addr;
        int ret;
        struct ospf_if_params *params;
 
        params = IF_DEF_PARAMS(ifp);
 
-       if (argc == 5) {
+       if (argv[idx_ipv4]->type == IPV4_TKN) {
                ret = inet_aton(argv[idx_ipv4]->arg, &addr);
                if (!ret) {
                        vty_out(vty,
@@ -7575,6 +7623,17 @@ DEFUN (ip_ospf_authentication_args,
        if (argv[idx_encryption]->arg[0] == 'm') {
                SET_IF_PARAM(params, auth_type);
                params->auth_type = OSPF_AUTH_CRYPTOGRAPHIC;
+               UNSET_IF_PARAM(params, keychain_name);
+               XFREE(MTYPE_OSPF_IF_PARAMS, params->keychain_name);
+               return CMD_SUCCESS;
+       }
+
+       if (argv[idx_encryption]->arg[0] == 'k') {
+               SET_IF_PARAM(params, auth_type);
+               params->auth_type = OSPF_AUTH_CRYPTOGRAPHIC;
+               SET_IF_PARAM(params, keychain_name);
+               params->keychain_name = XSTRDUP(MTYPE_OSPF_IF_PARAMS, argv[idx_encryption+1]->arg);
+               UNSET_IF_PARAM(params, auth_crypt);
                return CMD_SUCCESS;
        }
 
@@ -7618,18 +7677,20 @@ DEFUN (ip_ospf_authentication,
 
 DEFUN (no_ip_ospf_authentication_args,
        no_ip_ospf_authentication_args_addr_cmd,
-       "no ip ospf authentication <null|message-digest> [A.B.C.D]",
+       "no ip ospf authentication <null|message-digest|key-chain [KEYCHAIN_NAME]> [A.B.C.D]",
        NO_STR
        "IP Information\n"
        "OSPF interface commands\n"
        "Enable authentication on this interface\n"
        "Use null authentication\n"
        "Use message-digest authentication\n"
+          "Use a key-chain for cryptographic authentication keys\n"
+          "Key-chain name\n"
        "Address of interface\n")
 {
        VTY_DECLVAR_CONTEXT(interface, ifp);
        int idx_encryption = 4;
-       int idx_ipv4 = 5;
+       int idx_ipv4 = argc-1;
        struct in_addr addr;
        int ret;
        struct ospf_if_params *params;
@@ -7638,7 +7699,7 @@ DEFUN (no_ip_ospf_authentication_args,
 
        params = IF_DEF_PARAMS(ifp);
 
-       if (argc == 6) {
+       if (argv[idx_ipv4]->type == IPV4_TKN) {
                ret = inet_aton(argv[idx_ipv4]->arg, &addr);
                if (!ret) {
                        vty_out(vty,
@@ -7653,6 +7714,10 @@ DEFUN (no_ip_ospf_authentication_args,
                }
                params->auth_type = OSPF_AUTH_NOTSET;
                UNSET_IF_PARAM(params, auth_type);
+
+               XFREE(MTYPE_OSPF_IF_PARAMS, params->keychain_name);
+               UNSET_IF_PARAM(params, keychain_name);
+
                if (params != IF_DEF_PARAMS(ifp)) {
                        ospf_free_if_params(ifp, addr);
                        ospf_if_update_params(ifp, addr);
@@ -7660,7 +7725,8 @@ DEFUN (no_ip_ospf_authentication_args,
        } else {
                if (argv[idx_encryption]->arg[0] == 'n') {
                        auth_type = OSPF_AUTH_NULL;
-               } else if (argv[idx_encryption]->arg[0] == 'm') {
+               } else if (argv[idx_encryption]->arg[0] == 'm' ||
+                                  argv[idx_encryption]->arg[0] == 'k') {
                        auth_type = OSPF_AUTH_CRYPTOGRAPHIC;
                } else {
                        vty_out(vty, "Unexpected input encountered\n");
@@ -7676,6 +7742,8 @@ DEFUN (no_ip_ospf_authentication_args,
                if (params->auth_type == auth_type) {
                        params->auth_type = OSPF_AUTH_NOTSET;
                        UNSET_IF_PARAM(params, auth_type);
+                       XFREE(MTYPE_OSPF_IF_PARAMS, params->keychain_name);
+                       UNSET_IF_PARAM(params, keychain_name);
                }
 
                for (rn = route_top(IF_OIFS_PARAMS(ifp)); rn;
@@ -7684,6 +7752,8 @@ DEFUN (no_ip_ospf_authentication_args,
                                if (params->auth_type == auth_type) {
                                        params->auth_type = OSPF_AUTH_NOTSET;
                                        UNSET_IF_PARAM(params, auth_type);
+                                       XFREE(MTYPE_OSPF_IF_PARAMS, params->keychain_name);
+                                       UNSET_IF_PARAM(params, keychain_name);
                                        if (params != IF_DEF_PARAMS(ifp)) {
                                                ospf_free_if_params(
                                                        ifp, rn->p.u.prefix4);
@@ -12098,11 +12168,11 @@ static const char *const ospf_int_type_str[] = {
        "loopback"
 };
 
-static const char *interface_config_auth_str(struct ospf_if_params *params)
+static int interface_config_auth_str(struct ospf_if_params *params, char *buf)
 {
        if (!OSPF_IF_PARAM_CONFIGURED(params, auth_type)
            || params->auth_type == OSPF_AUTH_NOTSET)
-               return NULL;
+               return 0;
 
        /* Translation tables are not that much help
         * here due to syntax
@@ -12110,16 +12180,22 @@ static const char *interface_config_auth_str(struct ospf_if_params *params)
        switch (params->auth_type) {
 
        case OSPF_AUTH_NULL:
-               return " null";
+               snprintf(buf, BUFSIZ, " null");
+               break;
 
        case OSPF_AUTH_SIMPLE:
-               return "";
+               snprintf(buf, BUFSIZ, " ");
+               break;
 
        case OSPF_AUTH_CRYPTOGRAPHIC:
-               return " message-digest";
+               if (OSPF_IF_PARAM_CONFIGURED(params, keychain_name))
+                       snprintf(buf, BUFSIZ, " key-chain %s", params->keychain_name);
+               else
+                       snprintf(buf, BUFSIZ, " message-digest");
+               break;
        }
 
-       return "";
+       return 1;
 }
 
 static int config_write_interface_one(struct vty *vty, struct vrf *vrf)
@@ -12129,7 +12205,8 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf)
        struct crypt_key *ck;
        struct route_node *rn = NULL;
        struct ospf_if_params *params;
-       const char *auth_str;
+       char buf[BUFSIZ];
+       int ret = 0;
        int write = 0;
 
        FOR_ALL_INTERFACES (vrf, ifp) {
@@ -12170,10 +12247,10 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf)
                        }
 
                        /* OSPF interface authentication print */
-                       auth_str = interface_config_auth_str(params);
-                       if (auth_str) {
+                       ret = interface_config_auth_str(params, buf);
+                       if (ret) {
                                vty_out(vty, " ip ospf authentication%s",
-                                       auth_str);
+                                       buf);
                                if (params != IF_DEF_PARAMS(ifp) && rn)
                                        vty_out(vty, " %pI4",
                                                &rn->p.u.prefix4);
@@ -12613,8 +12690,9 @@ static int config_write_virtual_link(struct vty *vty, struct ospf *ospf)
 {
        struct listnode *node;
        struct ospf_vl_data *vl_data;
-       const char *auth_str;
        char buf[INET_ADDRSTRLEN];
+       char buf2[BUFSIZ];
+       int ret = 0;
 
        /* Virtual-Link print */
        for (ALL_LIST_ELEMENTS_RO(ospf->vlinks, node, vl_data)) {
@@ -12647,12 +12725,12 @@ static int config_write_virtual_link(struct vty *vty, struct ospf *ospf)
                                vty_out(vty, " area %s virtual-link %pI4\n", buf,
                                        &vl_data->vl_peer);
                        /* Auth type */
-                       auth_str = interface_config_auth_str(
-                               IF_DEF_PARAMS(oi->ifp));
-                       if (auth_str)
+                       ret = interface_config_auth_str(
+                               IF_DEF_PARAMS(oi->ifp), buf2);
+                       if (ret)
                                vty_out(vty,
                                        " area %s virtual-link %pI4 authentication%s\n",
-                                       buf, &vl_data->vl_peer, auth_str);
+                                       buf, &vl_data->vl_peer, buf2);
                        /* Auth key */
                        if (IF_DEF_PARAMS(vl_data->vl_oi->ifp)->auth_simple[0]
                            != '\0')
index 44ee3b0f13a957320bff37b98a9b7afd38cf82ba..4803aae68d8435dfa97a7e7bf0e294ca354b1b4e 100644 (file)
@@ -56,6 +56,7 @@ ospfd_libfrrospf_a_SOURCES = \
        ospfd/ospf_zebra.c \
        ospfd/ospfd.c \
        ospfd/ospf_gr_helper.c \
+       ospfd/ospf_auth.c \
        # end
 
 if OSPFD
@@ -106,6 +107,7 @@ noinst_HEADERS += \
        ospfd/ospf_te.h \
        ospfd/ospf_vty.h \
        ospfd/ospf_zebra.h \
+       ospfd/ospf_auth.h \
        # end
 
 ospfd_ospfd_LDADD = ospfd/libfrrospf.a ospfd/libfrrospfclient.a lib/libfrr.la $(LIBCAP) $(LIBM)
index 6dd5c8866ed473fc399100a52acddcee49a9913e..0a7e28ec7ac1e2866b1f32739baccfedf8b87fb8 100644 (file)
@@ -36,7 +36,7 @@ daemon_flags = {
     "lib/filter.c": "VTYSH_ACL",
     "lib/filter_cli.c": "VTYSH_ACL",
     "lib/if.c": "VTYSH_INTERFACE",
-    "lib/keychain.c": "VTYSH_RIPD|VTYSH_EIGRPD|VTYSH_OSPF6D",
+    "lib/keychain.c": "VTYSH_KEYS",
     "lib/mgmt_be_client.c": "VTYSH_STATICD",
     "lib/mgmt_fe_client.c": "VTYSH_MGMTD",
     "lib/lib_vty.c": "VTYSH_ALL",
index 5486e904df74c453093874a0ebd7ec010723663e..5b18f8b679ceaae656f615b6e5f18dceff43e162 100644 (file)
@@ -426,6 +426,10 @@ def config_ospf_interface(
                     cmd = "ip ospf authentication null"
                 elif data_ospf_auth == "message-digest":
                     cmd = "ip ospf authentication message-digest"
+                elif data_ospf_auth == "key-chain":
+                    cmd = "ip ospf authentication key-chain {}".format(
+                        ospf_data["keychain"]
+                    )
                 else:
                     cmd = "ip ospf authentication"
 
index 88219b84006e7612d3e694f151348dad084bc2f1..8dd103013b4eb4df5832603778a083554df3ee8d 100644 (file)
@@ -64,7 +64,9 @@ TOPOOLOGY =
 TESTCASES =
 1. Verify ospf authentication with Simple password authentication.
 2. Verify ospf authentication with MD5 authentication.
-3. Verify ospf authentication with different authentication methods.
+3. Verify ospf authentication with MD5 keychain authentication.
+4. Verify ospf authentication with SHA256 keychain authentication.
+5. Verify ospf authentication with different authentication methods.
 
  """
 
@@ -535,7 +537,477 @@ def test_ospf_authentication_md5_tc29_p1(request):
     write_test_footer(tc_name)
 
 
-def test_ospf_authentication_different_auths_tc30_p1(request):
+def test_ospf_authentication_md5_keychain_tc30_p1(request):
+    """
+    OSPF Authentication - Verify ospf authentication with MD5 authentication.
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+    global topo
+    step("Bring up the base config.")
+    reset_config_on_routers(tgen)
+    step(
+        "Configure ospf with on R1 and R2, enable ospf on R1 interface "
+        "connected to R2 with message-digest authentication using  ip "
+        "ospf authentication key-chain cmd."
+    )
+
+    router1 = tgen.gears["r1"]
+    router2 = tgen.gears["r2"]
+
+    router1.vtysh_cmd(
+        """configure terminal
+           key chain auth
+             key 10
+               key-string ospf
+               cryptographic-algorithm md5"""
+    )
+
+    r1_ospf_auth = {
+        "r1": {
+            "links": {
+                "r2": {
+                    "ospf": {
+                        "authentication": "key-chain",
+                        "keychain": "auth",
+                    }
+                }
+            }
+        }
+    }
+    result = config_ospf_interface(tgen, topo, r1_ospf_auth)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    step("Verify that the neighbour is not FULL between R1 and R2.")
+    # wait for dead time expiry.
+    sleep(6)
+    dut = "r1"
+    ospf_covergence = verify_ospf_neighbor(
+        tgen, topo, dut=dut, expected=False, retry_timeout=6
+    )
+    assert ospf_covergence is not True, "Testcase Failed \n Error  {}".format(
+        ospf_covergence
+    )
+
+    step(
+        "On R2 enable ospf on interface with message-digest authentication"
+        "  using  ip ospf authentication  message-digest password cmd."
+    )
+
+    router2.vtysh_cmd(
+        """configure terminal
+           key chain auth
+             key 10
+               key-string ospf
+               cryptographic-algorithm md5"""
+    )
+
+    r2_ospf_auth = {
+        "r2": {
+            "links": {
+                "r1": {
+                    "ospf": {
+                        "authentication": "key-chain",
+                        "keychain": "auth",
+                    }
+                }
+            }
+        }
+    }
+    result = config_ospf_interface(tgen, topo, r2_ospf_auth)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    step(
+        "Verify that the neighbour is FULL between R1 and R2  "
+        "using show ip ospf neighbor cmd."
+    )
+
+    dut = "r2"
+    ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+    assert ospf_covergence is True, "Testcase Failed \n Error  {}".format(
+        ospf_covergence
+    )
+
+    step(
+        "Disable message-digest authentication on R2  using no ip ospf "
+        "authentication  key-chain cmd."
+    )
+
+    r2_ospf_auth = {
+        "r2": {
+            "links": {
+                "r1": {
+                    "ospf": {
+                        "authentication": "key-chain",
+                        "keychain": "auth",
+                        "del_action": True,
+                    }
+                }
+            }
+        }
+    }
+    result = config_ospf_interface(tgen, topo, r2_ospf_auth)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    step("Verify on R1 ,nbr is deleted for R2 after dead interval expiry")
+    #  wait till the dead timer expiry
+    sleep(6)
+    dut = "r2"
+    ospf_covergence = verify_ospf_neighbor(
+        tgen, topo, dut=dut, expected=False, retry_timeout=10
+    )
+    assert ospf_covergence is not True, "Testcase Failed \n Error  {}".format(
+        ospf_covergence
+    )
+
+    step("Again On R2 enable ospf on interface with key-chain auth")
+    r2_ospf_auth = {
+        "r2": {
+            "links": {
+                "r1": {
+                    "ospf": {
+                        "authentication": "key-chain",
+                        "keychain": "auth",
+                    }
+                }
+            }
+        }
+    }
+    result = config_ospf_interface(tgen, topo, r2_ospf_auth)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    step(
+        "Verify that the neighbour is FULL between R1 and R2 using"
+        " show ip ospf neighbor cmd."
+    )
+
+    dut = "r2"
+    ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+    assert ospf_covergence is True, "Testcase Failed \n Error  {}".format(
+        ospf_covergence
+    )
+
+    step("Shut no shut interface on R1")
+    dut = "r1"
+    intf = topo["routers"]["r1"]["links"]["r2"]["interface"]
+    shutdown_bringup_interface(tgen, dut, intf, False)
+
+    dut = "r2"
+    step(
+        "Verify that the neighbour is not FULL between R1 and R2 using "
+        "show ip ospf neighbor cmd."
+    )
+    ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut, expected=False)
+    assert ospf_covergence is not True, "Testcase Failed \n Error  {}".format(
+        ospf_covergence
+    )
+
+    dut = "r1"
+    shutdown_bringup_interface(tgen, dut, intf, True)
+
+    step(
+        "Verify that the neighbour is FULL between R1 and R2 using "
+        "show ip ospf neighbor cmd."
+    )
+
+    dut = "r2"
+    ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+    assert ospf_covergence is True, "Testcase Failed \n Error  {}".format(
+        ospf_covergence
+    )
+
+    step("Change Ip address on R1 and R2")
+
+    topo_modify_change_ip = deepcopy(topo)
+
+    intf_ip = topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"]
+
+    topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"] = str(
+        IPv4Address(frr_unicode(intf_ip.split("/")[0])) + 3
+    ) + "/{}".format(intf_ip.split("/")[1])
+
+    build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
+
+    reset_config_on_routers(tgen, routerName="r1")
+    dut = "r1"
+    intf = topo["routers"]["r1"]["links"]["r2"]["interface"]
+    shutdown_bringup_interface(tgen, dut, intf, False)
+    shutdown_bringup_interface(tgen, dut, intf, True)
+    clear_ospf(tgen, "r1")
+    router1.vtysh_cmd(
+        """configure terminal
+           key chain auth
+             key 10
+               key-string ospf
+               cryptographic-algorithm md5"""
+    )
+    r1_ospf_auth = {
+        "r1": {
+            "links": {
+                "r2": {
+                    "ospf": {
+                        "authentication": "key-chain",
+                        "keychain": "auth",
+                    }
+                }
+            }
+        }
+    }
+    result = config_ospf_interface(tgen, topo, r1_ospf_auth)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    step(
+        "Verify that the neighbour is FULL between R1 and R2 with new "
+        "ip address using show ip ospf "
+    )
+
+    dut = "r1"
+    ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+    assert ospf_covergence is True, "Testcase Failed \n Error  {}".format(
+        ospf_covergence
+    )
+
+    write_test_footer(tc_name)
+
+
+def test_ospf_authentication_sha256_keychain_tc32_p1(request):
+    """
+    OSPF Authentication - Verify ospf authentication with MD5 authentication.
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+    global topo
+    step("Bring up the base config.")
+    reset_config_on_routers(tgen)
+    step(
+        "Configure ospf with on R1 and R2, enable ospf on R1 interface "
+        "connected to R2 with message-digest authentication using  ip "
+        "ospf authentication key-chain cmd."
+    )
+
+    router1 = tgen.gears["r1"]
+    router2 = tgen.gears["r2"]
+
+    router1.vtysh_cmd(
+        """configure terminal
+           key chain auth
+             key 10
+               key-string ospf
+               cryptographic-algorithm hmac-sha-256"""
+    )
+
+    r1_ospf_auth = {
+        "r1": {
+            "links": {
+                "r2": {
+                    "ospf": {
+                        "authentication": "key-chain",
+                        "keychain": "auth",
+                    }
+                }
+            }
+        }
+    }
+    result = config_ospf_interface(tgen, topo, r1_ospf_auth)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    step("Verify that the neighbour is not FULL between R1 and R2.")
+    # wait for dead time expiry.
+    sleep(6)
+    dut = "r1"
+    ospf_covergence = verify_ospf_neighbor(
+        tgen, topo, dut=dut, expected=False, retry_timeout=6
+    )
+    assert ospf_covergence is not True, "Testcase Failed \n Error  {}".format(
+        ospf_covergence
+    )
+
+    step(
+        "On R2 enable ospf on interface with message-digest authentication"
+        "  using  ip ospf authentication  message-digest password cmd."
+    )
+
+    router2.vtysh_cmd(
+        """configure terminal
+           key chain auth
+             key 10
+               key-string ospf
+               cryptographic-algorithm hmac-sha-256"""
+    )
+
+    r2_ospf_auth = {
+        "r2": {
+            "links": {
+                "r1": {
+                    "ospf": {
+                        "authentication": "key-chain",
+                        "keychain": "auth",
+                    }
+                }
+            }
+        }
+    }
+    result = config_ospf_interface(tgen, topo, r2_ospf_auth)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    step(
+        "Verify that the neighbour is FULL between R1 and R2  "
+        "using show ip ospf neighbor cmd."
+    )
+
+    dut = "r2"
+    ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+    assert ospf_covergence is True, "Testcase Failed \n Error  {}".format(
+        ospf_covergence
+    )
+
+    step(
+        "Disable message-digest authentication on R2  using no ip ospf "
+        "authentication  key-chain cmd."
+    )
+
+    r2_ospf_auth = {
+        "r2": {
+            "links": {
+                "r1": {
+                    "ospf": {
+                        "authentication": "key-chain",
+                        "keychain": "auth",
+                        "del_action": True,
+                    }
+                }
+            }
+        }
+    }
+    result = config_ospf_interface(tgen, topo, r2_ospf_auth)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    step("Verify on R1 ,nbr is deleted for R2 after dead interval expiry")
+    #  wait till the dead timer expiry
+    sleep(6)
+    dut = "r2"
+    ospf_covergence = verify_ospf_neighbor(
+        tgen, topo, dut=dut, expected=False, retry_timeout=10
+    )
+    assert ospf_covergence is not True, "Testcase Failed \n Error  {}".format(
+        ospf_covergence
+    )
+
+    step("Again On R2 enable ospf on interface with key-chain auth")
+    r2_ospf_auth = {
+        "r2": {
+            "links": {
+                "r1": {
+                    "ospf": {
+                        "authentication": "key-chain",
+                        "keychain": "auth",
+                    }
+                }
+            }
+        }
+    }
+    result = config_ospf_interface(tgen, topo, r2_ospf_auth)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    step(
+        "Verify that the neighbour is FULL between R1 and R2 using"
+        " show ip ospf neighbor cmd."
+    )
+
+    dut = "r2"
+    ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+    assert ospf_covergence is True, "Testcase Failed \n Error  {}".format(
+        ospf_covergence
+    )
+
+    step("Shut no shut interface on R1")
+    dut = "r1"
+    intf = topo["routers"]["r1"]["links"]["r2"]["interface"]
+    shutdown_bringup_interface(tgen, dut, intf, False)
+
+    dut = "r2"
+    step(
+        "Verify that the neighbour is not FULL between R1 and R2 using "
+        "show ip ospf neighbor cmd."
+    )
+    ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut, expected=False)
+    assert ospf_covergence is not True, "Testcase Failed \n Error  {}".format(
+        ospf_covergence
+    )
+
+    dut = "r1"
+    shutdown_bringup_interface(tgen, dut, intf, True)
+
+    step(
+        "Verify that the neighbour is FULL between R1 and R2 using "
+        "show ip ospf neighbor cmd."
+    )
+
+    dut = "r2"
+    ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+    assert ospf_covergence is True, "Testcase Failed \n Error  {}".format(
+        ospf_covergence
+    )
+
+    step("Change Ip address on R1 and R2")
+
+    topo_modify_change_ip = deepcopy(topo)
+
+    intf_ip = topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"]
+
+    topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"] = str(
+        IPv4Address(frr_unicode(intf_ip.split("/")[0])) + 3
+    ) + "/{}".format(intf_ip.split("/")[1])
+
+    build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
+
+    reset_config_on_routers(tgen, routerName="r1")
+    dut = "r1"
+    intf = topo["routers"]["r1"]["links"]["r2"]["interface"]
+    shutdown_bringup_interface(tgen, dut, intf, False)
+    shutdown_bringup_interface(tgen, dut, intf, True)
+    clear_ospf(tgen, "r1")
+    router1.vtysh_cmd(
+        """configure terminal
+           key chain auth
+             key 10
+               key-string ospf
+               cryptographic-algorithm hmac-sha-256"""
+    )
+    r1_ospf_auth = {
+        "r1": {
+            "links": {
+                "r2": {
+                    "ospf": {
+                        "authentication": "key-chain",
+                        "keychain": "auth",
+                    }
+                }
+            }
+        }
+    }
+    result = config_ospf_interface(tgen, topo, r1_ospf_auth)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    step(
+        "Verify that the neighbour is FULL between R1 and R2 with new "
+        "ip address using show ip ospf "
+    )
+
+    dut = "r1"
+    ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+    assert ospf_covergence is True, "Testcase Failed \n Error  {}".format(
+        ospf_covergence
+    )
+
+    write_test_footer(tc_name)
+
+
+def test_ospf_authentication_different_auths_tc35_p1(request):
     """
     OSPF Authentication - Verify ospf authentication with different
     authentication methods.
@@ -553,6 +1025,9 @@ def test_ospf_authentication_different_auths_tc30_p1(request):
         "ospf authentication  message-digest cmd."
     )
 
+    router1 = tgen.gears["r1"]
+    router2 = tgen.gears["r2"]
+
     r1_ospf_auth = {
         "r1": {
             "links": {
@@ -769,16 +1244,23 @@ def test_ospf_authentication_different_auths_tc30_p1(request):
         ospf_covergence
     )
 
-    step("Enable Md5 authentication on the interface")
+    step("Enable SHA-256 authentication on the interface")
+
+    router1.vtysh_cmd(
+        """configure terminal
+           key chain auth
+             key 10
+               key-string ospf
+               cryptographic-algorithm hmac-sha-256"""
+    )
 
     r1_ospf_auth = {
         "r1": {
             "links": {
                 "r2": {
                     "ospf": {
-                        "authentication": "message-digest",
-                        "authentication-key": "ospf",
-                        "message-digest-key": "10",
+                        "authentication": "key-chain",
+                        "keychain": "auth",
                     }
                 }
             }
@@ -787,14 +1269,21 @@ def test_ospf_authentication_different_auths_tc30_p1(request):
     result = config_ospf_interface(tgen, topo, r1_ospf_auth)
     assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
 
+    router2.vtysh_cmd(
+        """configure terminal
+           key chain auth
+             key 10
+               key-string ospf
+               cryptographic-algorithm hmac-sha-256"""
+    )
+
     r2_ospf_auth = {
         "r2": {
             "links": {
                 "r1": {
                     "ospf": {
-                        "authentication": "message-digest",
-                        "authentication-key": "ospf",
-                        "message-digest-key": "10",
+                        "authentication": "key-chain",
+                        "keychain": "auth",
                     }
                 }
             }
@@ -814,39 +1303,27 @@ def test_ospf_authentication_different_auths_tc30_p1(request):
         ospf_covergence
     )
 
-    step("Change the MD5 authentication password")
+    step("Change the SHA-256 authentication password")
 
-    r1_ospf_auth = {
-        "r1": {
-            "links": {
-                "r2": {
-                    "ospf": {
-                        "authentication": "message-digest",
-                        "authentication-key": "OSPFv4",
-                        "message-digest-key": "10",
-                    }
-                }
-            }
-        }
-    }
-    result = config_ospf_interface(tgen, topo, r1_ospf_auth)
-    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+    router1.vtysh_cmd(
+        """configure terminal
+           key chain auth
+             key 10
+               key-string OSPFv4
+               cryptographic-algorithm hmac-sha-512"""
+    )
 
-    r2_ospf_auth = {
-        "r2": {
-            "links": {
-                "r1": {
-                    "ospf": {
-                        "authentication": "message-digest",
-                        "authentication-key": "OSPFv4",
-                        "message-digest-key": "10",
-                    }
-                }
-            }
-        }
-    }
-    result = config_ospf_interface(tgen, topo, r2_ospf_auth)
-    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+    router2.vtysh_cmd(
+        """configure terminal
+           key chain auth
+             key 10
+               key-string OSPFv4
+               cryptographic-algorithm hmac-sha-512"""
+    )
+    ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+    assert ospf_covergence is True, "Testcase Failed \n Error  {}".format(
+        ospf_covergence
+    )
 
     write_test_footer(tc_name)
 
index 9d67003f35d51e5cee1feacac90d6ed7abfea877..65733ca61b4c9b10b790972311d3f1aa3edf2b85 100644 (file)
@@ -59,7 +59,7 @@ extern struct event_loop *master;
                VTYSH_VRRPD
 #define VTYSH_INTERFACE VTYSH_INTERFACE_SUBSET | VTYSH_BGPD
 #define VTYSH_VRF      VTYSH_INTERFACE_SUBSET | VTYSH_MGMTD
-#define VTYSH_KEYS VTYSH_RIPD | VTYSH_EIGRPD | VTYSH_OSPF6D
+#define VTYSH_KEYS VTYSH_RIPD | VTYSH_EIGRPD | VTYSH_OSPF6D | VTYSH_OSPFD
 /* Daemons who can process nexthop-group configs */
 #define VTYSH_NH_GROUP    VTYSH_PBRD|VTYSH_SHARPD
 #define VTYSH_SR          VTYSH_ZEBRA|VTYSH_PATHD