diff options
| author | Mahdi Varasteh <varasteh@amnesh.ir> | 2023-09-12 15:09:44 +0330 | 
|---|---|---|
| committer | Mahdi Varasteh <varasteh@amnesh.ir> | 2023-09-16 07:38:23 +0330 | 
| commit | f5011cd5ddfd0eabe359d7013747823c6bd4ed3f (patch) | |
| tree | 0be666457c571176705bb970582b16fc4d2d688b /ospfd | |
| parent | edd243280c56018e413a5773b2e8cb82d8be8421 (diff) | |
[ospfd]: add support for RFC 5709 HMAC-SHA Auth
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>
Diffstat (limited to 'ospfd')
| -rw-r--r-- | ospfd/ospf_auth.c | 705 | ||||
| -rw-r--r-- | ospfd/ospf_auth.h | 20 | ||||
| -rw-r--r-- | ospfd/ospf_errors.c | 6 | ||||
| -rw-r--r-- | ospfd/ospf_errors.h | 2 | ||||
| -rw-r--r-- | ospfd/ospf_interface.c | 3 | ||||
| -rw-r--r-- | ospfd/ospf_interface.h | 7 | ||||
| -rw-r--r-- | ospfd/ospf_main.c | 2 | ||||
| -rw-r--r-- | ospfd/ospf_packet.c | 363 | ||||
| -rw-r--r-- | ospfd/ospf_vty.c | 142 | ||||
| -rw-r--r-- | ospfd/subdir.am | 2 | 
10 files changed, 864 insertions, 388 deletions
diff --git a/ospfd/ospf_auth.c b/ospfd/ospf_auth.c new file mode 100644 index 0000000000..2d13d4e9ad --- /dev/null +++ b/ospfd/ospf_auth.c @@ -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 index 0000000000..6f6d3db588 --- /dev/null +++ b/ospfd/ospf_auth.h @@ -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 */ diff --git a/ospfd/ospf_errors.c b/ospfd/ospf_errors.c index 16aa3ab526..cf58c6ad8b 100644 --- a/ospfd/ospf_errors.c +++ b/ospfd/ospf_errors.c @@ -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",  	},  	{ diff --git a/ospfd/ospf_errors.h b/ospfd/ospf_errors.h index dcf9a65ce9..e63cb7409c 100644 --- a/ospfd/ospf_errors.h +++ b/ospfd/ospf_errors.h @@ -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, diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index bdab672b47..7601419325 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -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; diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index 47b70f8039..e2290a881c 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -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); diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 536bd592d2..dd000241f4 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -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); diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index cfa0d5d574..b37efa3efa 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -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) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 158e90df59..8c3ad7f372 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -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') diff --git a/ospfd/subdir.am b/ospfd/subdir.am index 44ee3b0f13..4803aae68d 100644 --- a/ospfd/subdir.am +++ b/ospfd/subdir.am @@ -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)  | 
