diff -upwbNr quagga-0.99.21/lib/cryptohash.c quagga-rfc6506/lib/cryptohash.c --- quagga-0.99.21/lib/cryptohash.c 1970-01-01 05:30:00.000000000 +0530 +++ quagga-rfc6506/lib/cryptohash.c 2013-07-10 10:11:00.000000000 +0530 @@ -0,0 +1,272 @@ +/* + * This file, a part of Quagga, implements an interface to crypto hashes. + * + * + * Quagga is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * Quagga is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Quagga; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include +#include "cryptohash.h" +#include "md5.h" +#include "command.h" + +#ifdef HAVE_LIBGCRYPT +#define GCRYPT_NO_DEPRECATED +#include +#endif /* HAVE_LIBGCRYPT */ + +const struct message hash_algo_str[] = +{ + { HASH_KEYED_MD5, "Keyed-MD5" }, + { HASH_HMAC_SHA1, "HMAC-SHA-1" }, + { HASH_HMAC_SHA256, "HMAC-SHA-256" }, + { HASH_HMAC_SHA384, "HMAC-SHA-384" }, + { HASH_HMAC_SHA512, "HMAC-SHA-512" }, + { HASH_HMAC_RMD160, "HMAC-RIPEMD-160" }, + { HASH_HMAC_WHIRLPOOL, "HMAC-Whirlpool" }, +}; +const size_t hash_algo_str_max = sizeof (hash_algo_str) / sizeof (struct message); + +/* hash_algo_byname() assumes this array to be exactly HASH_ALGO_MAX items big */ +const struct message hash_algo_cli_str[] = +{ + { HASH_KEYED_MD5, "md5" }, + { HASH_HMAC_SHA1, "sha1" }, + { HASH_HMAC_SHA256, "sha256" }, + { HASH_HMAC_SHA384, "sha384" }, + { HASH_HMAC_SHA512, "sha512" }, + { HASH_HMAC_RMD160, "rmd160" }, + { HASH_HMAC_WHIRLPOOL, "whirlpool" }, +}; +const size_t hash_algo_cli_str_max = sizeof (hash_algo_cli_str) / sizeof (struct message); + +/* hash digest size map */ +const u_int8_t hash_digest_length[] = +{ + [HASH_KEYED_MD5] = HASH_SIZE_MD5, + [HASH_HMAC_SHA1] = HASH_SIZE_SHA1, + [HASH_HMAC_SHA256] = HASH_SIZE_SHA256, + [HASH_HMAC_SHA384] = HASH_SIZE_SHA384, + [HASH_HMAC_SHA512] = HASH_SIZE_SHA512, + [HASH_HMAC_RMD160] = HASH_SIZE_RMD160, + [HASH_HMAC_WHIRLPOOL] = HASH_SIZE_WHIRLPOOL, +}; + +/* RFC4822 2.5: Apad is the hexadecimal value 0x878FE1F3 repeated (L/4) times. */ +const u_int8_t hash_apad_sha512[HASH_SIZE_SHA512] = +{ + 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, + 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, + 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, + 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, + 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, + 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, + 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, + 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, +}; + +#ifdef HAVE_LIBGCRYPT +/* ripd to gcrypto hash algorithm code map */ +static const int hash_gcrypt_algo_map[] = +{ + [HASH_HMAC_SHA1] = GCRY_MD_SHA1, + [HASH_HMAC_SHA256] = GCRY_MD_SHA256, + [HASH_HMAC_SHA384] = GCRY_MD_SHA384, + [HASH_HMAC_SHA512] = GCRY_MD_SHA512, + [HASH_HMAC_RMD160] = GCRY_MD_RMD160, + [HASH_HMAC_WHIRLPOOL] = GCRY_MD_WHIRLPOOL, +}; +#endif /* HAVE_LIBGCRYPT */ + +/* available only in processes with a call to hash_library_init() */ +DEFUN (show_crypto, + show_crypto_cmd, + "show crypto", + SHOW_STR + "Crypto module information\n") +{ +#ifdef HAVE_LIBGCRYPT + unsigned i; + vty_out (vty, "Compiled with libgcrypt version %s%s", GCRYPT_VERSION, VTY_NEWLINE); + vty_out (vty, "Running with libgcrypt version %s%s", gcry_check_version (NULL), VTY_NEWLINE); + for (i = 0; i < sizeof (hash_gcrypt_algo_map) / sizeof (hash_gcrypt_algo_map[0]); i++) + if (hash_gcrypt_algo_map[i]) + vty_out (vty, "%-17s: %s%s", LOOKUP (hash_algo_str, i), + hash_algo_enabled (i) ? "enabled" : "disabled", VTY_NEWLINE); +#else + vty_out (vty, "Compiled without libgcrypt%s", VTY_NEWLINE); +#endif /* HAVE_LIBGCRYPT */ + return CMD_SUCCESS; +} + +extern unsigned +hash_library_init (void) +{ +#ifdef HAVE_LIBGCRYPT + if (! gcry_check_version (GCRYPT_VERSION)) + { + zlog_err ("libgcrypt initialization failed"); + return 1; + } + gcry_control (GCRYCTL_DISABLE_SECMEM, 0); + gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); + install_element (VIEW_NODE, &show_crypto_cmd); + install_element (ENABLE_NODE, &show_crypto_cmd); +#endif /* HAVE_LIBGCRYPT */ + return 0; +} + +/* Map a string name of a listed hash algorithm into Quagga internal code. */ +unsigned +hash_algo_byname (const char *algo) +{ + unsigned i; + + for (i = 0; i < HASH_ALGO_MAX; i++) + if (! strcmp (algo, hash_algo_cli_str[i].str)) + return hash_algo_cli_str[i].key; + return 0; +} + +/* Test whether a hash algorithm with the given Quagga code is available in the + * current runtime. Using this function requires neither libgcrypt presence nor + * knowing libgcrypt internal code for the hash algorithm. */ +unsigned char +hash_algo_enabled (const unsigned hash_algo) +{ + switch (hash_algo) + { + case HASH_KEYED_MD5: + return 1; +#ifdef HAVE_LIBGCRYPT + case HASH_HMAC_SHA1: + case HASH_HMAC_SHA256: + case HASH_HMAC_SHA384: + case HASH_HMAC_SHA512: + case HASH_HMAC_RMD160: + case HASH_HMAC_WHIRLPOOL: + return 0 == gcry_md_test_algo (hash_gcrypt_algo_map[hash_algo]); +#endif /* HAVE_LIBGCRYPT */ + default: + return 0; + } +} + +/* Process input data with Keyed-MD5 algorithm and store digest as output. */ +unsigned +hash_make_keyed_md5 +( + const void *input, + const size_t inputlen, + const void *auth_str, + const size_t auth_str_len, + void *output +) +{ + char auth_str_padded[HASH_SIZE_MD5] = { 0 }; + MD5_CTX ctx; + + memcpy (auth_str_padded, auth_str, MIN (HASH_SIZE_MD5, auth_str_len)); + memset (&ctx, 0, sizeof (ctx)); + MD5Init (&ctx); + MD5Update (&ctx, input, inputlen); + MD5Update (&ctx, auth_str_padded, HASH_SIZE_MD5); + MD5Final (output, &ctx); + return 0; +} + +#ifdef HAVE_LIBGCRYPT +/* Process input data with a HMAC algorithm using the given hash function and + * store digest as output. It is safe for output digest buffer to be within + * input buffer. */ +unsigned +hash_make_hmac +( + const unsigned hash_algo, + const void *input, + const size_t inputlen, + const void *auth_str, + const size_t authlen, + void *output +) +{ + gcry_md_hd_t ctx; + + if (gcry_md_open (&ctx, hash_gcrypt_algo_map[hash_algo], GCRY_MD_FLAG_HMAC)) + return 1; + /* gcrypt handles preparing the key, Ipad and Opad */ + if (gcry_md_setkey (ctx, auth_str, authlen)) + { + gcry_md_close (ctx); + return 2; + } + gcry_md_write (ctx, input, inputlen); + gcry_md_final (ctx); + memcpy (output, gcry_md_read (ctx, 0), hash_digest_length[hash_algo]); + gcry_md_close (ctx); + return 0; +} + +/* The construct defined in RFC4822 and reused in RFC5709, RFC6506 and probably + * other works is similar to HMAC (RFC2104) but is not HMAC, to be precise. The + * principal difference is in the key preparation step. The original RFC2104 + * construct defines Ko to be B octets long and derives Ko from K respectively, + * whereas RFC4822 construct defines Ko to be L octets long (L <= B). Since + * L < B for most modern hash functions, these two constructs produce different + * digests for the same Text and K, when length of K is greater than L but not + * greater than B. + * + * In practice this means, that an implementation of RFC4822 construct (e. g. + * ripd) can reuse an existing implementation of HMAC (e. g. libgcrypt) as long + * as the authentication key is pre-processed with the function below. At the + * same time, this processing must not be performed by an implementation of the + * original HMAC construct (e. g. babeld). + */ +void +hash_key_compress_rfc4822 +( + const unsigned hash_algo, + const void *orig_key_bytes, + const size_t orig_key_len, + void *compr_key_bytes, /* size must be >= hash_algo digest length */ + size_t *compr_key_len +) +{ + switch (hash_algo) + { + case HASH_HMAC_SHA1: + case HASH_HMAC_SHA256: + case HASH_HMAC_SHA384: + case HASH_HMAC_SHA512: + case HASH_HMAC_RMD160: + case HASH_HMAC_WHIRLPOOL: + if (orig_key_len > hash_digest_length[hash_algo] ) /* > L, Ko := H(K) */ + { + gcry_md_hash_buffer (hash_gcrypt_algo_map[hash_algo], compr_key_bytes, orig_key_bytes, orig_key_len); + *compr_key_len = hash_digest_length[hash_algo]; + } + else /* <= L */ + { + memset (compr_key_bytes, 0, hash_digest_length[hash_algo]); + memcpy (compr_key_bytes, orig_key_bytes, orig_key_len); + *compr_key_len = orig_key_len; + } + break; + default: + assert (0); + } +} +#endif /* HAVE_LIBGCRYPT */ diff -upwbNr quagga-0.99.21/lib/cryptohash.h quagga-rfc6506/lib/cryptohash.h --- quagga-0.99.21/lib/cryptohash.h 1970-01-01 05:30:00.000000000 +0530 +++ quagga-rfc6506/lib/cryptohash.h 2013-07-10 10:14:00.000000000 +0530 @@ -0,0 +1,60 @@ +/* + * This file, a part of Quagga, implements an interface to crypto hashes. + * + * + * Quagga is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * Quagga is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Quagga; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef QUAGGA_CRYPTOHASH_H +#define QUAGGA_CRYPTOHASH_H + +#include "log.h" + +#define HASH_KEYED_MD5 1 +#define HASH_HMAC_SHA1 2 +#define HASH_HMAC_SHA256 3 +#define HASH_HMAC_SHA384 4 +#define HASH_HMAC_SHA512 5 +#define HASH_HMAC_RMD160 6 +#define HASH_HMAC_WHIRLPOOL 7 +#define HASH_ALGO_MAX 7 + +#define HASH_SIZE_MD5 16U +#define HASH_SIZE_SHA1 20U +#define HASH_SIZE_SHA256 32U +#define HASH_SIZE_SHA384 48U +#define HASH_SIZE_SHA512 64U +#define HASH_SIZE_RMD160 20U +#define HASH_SIZE_WHIRLPOOL 64U +#define HASH_SIZE_MAX 64U + +extern const struct message hash_algo_str[]; +extern const size_t hash_algo_str_max; +extern const struct message hash_algo_cli_str[]; +extern const size_t hash_algo_cli_str_max; +extern const u_int8_t hash_digest_length[]; +extern const u_int8_t hash_apad_sha512[]; + +extern unsigned hash_library_init (void); +extern unsigned hash_algo_byname (const char *); +extern unsigned char hash_algo_enabled (const unsigned); +extern unsigned hash_make_keyed_md5 (const void *, const size_t, const void *, const size_t, void *); +#ifdef HAVE_LIBGCRYPT +extern unsigned hash_make_hmac (const unsigned, const void *, const size_t, const void *, const size_t, void *); +extern void hash_key_compress_rfc4822 (const unsigned, const void *, const size_t, void *, size_t *); +#endif /* HAVE_LIBGCRYPT */ + +#endif /* QUAGGA_CRYPTOHASH_H */ diff -upwbNr quagga-0.99.21/lib/Makefile.am quagga-rfc6506/lib/Makefile.am --- quagga-0.99.21/lib/Makefile.am 2012-05-02 01:10:13.000000000 +0530 +++ quagga-rfc6506/lib/Makefile.am 2013-07-10 10:14:00.000000000 +0530 @@ -12,7 +12,7 @@ libzebra_la_SOURCES = \ sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \ filter.c routemap.c distribute.c stream.c str.c log.c plist.c \ zclient.c sockopt.c smux.c md5.c if_rmap.c keychain.c privs.c \ - sigevent.c pqueue.c jhash.c memtypes.c workqueue.c + sigevent.c pqueue.c jhash.c memtypes.c workqueue.c cryptohash.c BUILT_SOURCES = memtypes.h route_types.h @@ -27,7 +27,7 @@ pkginclude_HEADERS = \ str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \ plist.h zclient.h sockopt.h smux.h md5.h if_rmap.h keychain.h \ privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \ - workqueue.h route_types.h + workqueue.h route_types.h cryptohash.h EXTRA_DIST = regex.c regex-gnu.h memtypes.awk route_types.pl route_types.txt diff -upwbNr quagga-0.99.21/lib/memtypes.c quagga-rfc6506/lib/memtypes.c --- quagga-0.99.21/lib/memtypes.c 2012-05-01 21:40:27.000000000 +0530 +++ quagga-rfc6506/lib/memtypes.c 2013-07-10 10:14:00.000000000 +0530 @@ -216,6 +216,7 @@ struct memory_list memory_list_ospf6[] = { { MTYPE_OSPF6_TOP, "OSPF6 top" }, { MTYPE_OSPF6_AREA, "OSPF6 area" }, + { MTYPE_OSPF6_CRYPT_KEY, "OSPF6 crypt key" }, { MTYPE_OSPF6_IF, "OSPF6 interface" }, { MTYPE_OSPF6_NEIGHBOR, "OSPF6 neighbor" }, { MTYPE_OSPF6_ROUTE, "OSPF6 route" }, diff -upwbNr quagga-0.99.21/lib/memtypes.h quagga-rfc6506/lib/memtypes.h --- quagga-0.99.21/lib/memtypes.h 2012-05-01 22:15:24.000000000 +0530 +++ quagga-rfc6506/lib/memtypes.h 2013-07-10 10:12:00.000000000 +0530 @@ -166,6 +166,7 @@ enum MTYPE_OSPF_MESSAGE, MTYPE_OSPF6_TOP, MTYPE_OSPF6_AREA, + MTYPE_OSPF6_CRYPT_KEY, MTYPE_OSPF6_IF, MTYPE_OSPF6_NEIGHBOR, MTYPE_OSPF6_ROUTE,