svn commit: r248271 - user/andre/tcp-ao/sys/netinet

Andre Oppermann andre at FreeBSD.org
Thu Mar 14 16:40:42 UTC 2013


Author: andre
Date: Thu Mar 14 16:40:42 2013
New Revision: 248271
URL: http://svnweb.freebsd.org/changeset/base/248271

Log:
  First skeleton of the TCP-AO segment authentication verification and
  computation functions.
  
   tcp_ao_mac()	Setup of authentication computation for IPv4 and IPv6
   tcp_ao_hmac()	HMAC-SHA-1-(96), RFC5926, Section 3.2.1
   tcp_ao_cmac()	AES-128-CMAC-(96), RFC5926, Section 3.2.2
   tcp_ao_md5()	legacy compatibility to TCP-MD5
  
  Sponsored by:	Juniper Networks

Modified:
  user/andre/tcp-ao/sys/netinet/tcp_ao.c

Modified: user/andre/tcp-ao/sys/netinet/tcp_ao.c
==============================================================================
--- user/andre/tcp-ao/sys/netinet/tcp_ao.c	Thu Mar 14 16:33:43 2013	(r248270)
+++ user/andre/tcp-ao/sys/netinet/tcp_ao.c	Thu Mar 14 16:40:42 2013	(r248271)
@@ -50,3 +50,212 @@
  *  legacy tcp-md5 can be brought and integrated into the tcp-ao framework.
  */
 
+/*
+ * The code below is skeleton code and not functional yet.
+ */
+
+/*
+ * The hash over the header has to be pieced together and a couple of
+ * fields need manipulation, like zero'ing and byte order conversion.
+ * Instead of doing it in-place and calling the hash update function
+ * for each we just copy everything into one place in the right order.
+ */
+struct tcp_ao_thopt {
+	struct tcphdr th;
+	uint8_t tho[TCP_MAXOLEN];
+};
+struct tcp_ao_pseudo {
+	uint32_t tap_sne;	/* sequence number extension */
+	union {
+		struct tap_ip {
+			struct ippseudo tap_ph4;
+			struct tcp_ao_thopt tap_th;
+		} tap_ip;
+		struct tap_ip6 {
+			struct ip6_phdr tap_ph6;
+			struct tcp_ao_thopt tap_th;
+		} tap_ip6;
+	} tap;
+	int tap_type;
+	int tap_len;
+} __packed;
+#define tap4	tap.tap_ip
+#define tap6	tap.tap_ip6
+
+/* Convenient functions not yet in existence. */
+ip_hdr2pseudo(struct ip *ip, struct ippseudo *ipp);
+ip6_hdr2pseudo(struct ip6_hdr *ip6, struct ip6pseudo *ipp6);
+ip_inc2pseudo(struct in_conninfo *inc, struct ippseudo *ipp);
+ip6_inc2pseudo(struct in_conninfo *inc, struct ip6pseudo *ipp6);
+
+/*
+ * Computation the authentication hash and return the result of the hash
+ * comparison.  Return values:
+ *  0     = success
+ *  EAUTH = authentication failed
+ *  other = authentication failed
+ */
+static int
+tcp_ao_mac(struct tcpcb *tp, struct tcp_ao_key *tk, struct in_conninfo *inc,
+    struct tcphdr *th, struct tcpopt *to, struct mbuf *m)
+{
+	int moff, mlen, thlen;
+	struct tcp_ao_pseudo ph;
+	struct tcp_ao_thopt *tho;
+	uint8_t hash[MAXHASHLEN];
+
+	/*
+	 * Set up the virtual sequence number extension that is part of
+	 * the authentication hash.
+	 */
+	if (tp != NULL)
+		ph.tap_sne = tp->t_ao->tao_sne;
+	else
+		ph.tap_sne = 0;
+
+	/* Fill in pseudo headers. */
+	switch(inc->inc_flags & INC_ISIPV6) {
+	case 0:
+		ip_inc2pseudo(inc, &ph.tap4.tap_ph4);
+		ph.tap_len += sizeof(ph.tap4.tap_ph4);
+		tho = &ph.tap4.tap_th;
+		break;
+	case INC_ISIPV6:
+		ip6_hdr2pseudo(inc, &ph.tap6.tap_ph6);
+		ph.tap_len += sizeof(ph.tap6.tap_ph6);
+		tho = &ph.tap6.tap_th;
+		break;
+	default:
+		error = EINVAL;
+		goto out;
+	}
+	ph.tap_len += sizeof(ph.tap_sne);
+
+	/* Fill in tcpheader including options. */
+	thlen = th->th_off << 2;
+	bcopy(th, tho, thlen);
+	ph.tap_len += thlen;
+
+	/* Zero out checksum and mac field and swap to network byte order. */
+	tho->th.th_sum = 0;
+	bzero(&tho->tho + (to->to_signature - (th + 1)), to->to_siglen);
+	tcp_fields_to_net(&tho);
+
+	/* Set up the mbuf length fields. */
+	moff = thlen;
+	mlen = m_length(m, NULL) - thlen;
+
+	switch(tk->algo) {
+	case TCP_AO_HMAC_SHA_1_96:
+		error = tcp_ao_sha1(tk->key, ph, m, moff, mlen, hash);
+		break;
+	case TCP_AO_AES_128_CMAC_96:
+		error = tcp_ao_cmac(tk->key, ph, m, moff, mlen, hash);
+		break;
+	case TCP_AO_TCPMD5:
+		error = tcp_ao_md5(tk->key, ph, m, moff, mlen, hash);
+		break;
+	default:
+		error = EINVAL;
+		goto out;
+	}
+	if (error)
+		goto out;
+
+	/* Compare result to segment signature. */
+	if (bcmp(hash, to->to_signature, tk->tk_hashlen));
+		error = EAUTH;
+
+out:
+	return (error);
+}
+
+/*
+ * Note: Can't use cryptodev because of callback based non-inline
+ * processing.  Also complexity to set up a crypto session is too high
+ * and requires a couple of malloc's.
+ */
+
+/*
+ * Compute RFC5925+RFC5926 compliant HMAC-SHA1 authentication MAC of
+ * a tcp segment.
+ * XXX: HMAC_SHA1 doesn't exist yet.
+ */
+static int
+tcp_ao_sha1(uint32_t key[static SHA1_BLOCK_LENGTH], struct pseudo *ph,
+    struct mbuf *m, int moff, int mlen, uint8_t hash[static SHA1_RESULTLEN])
+{
+	HMAC_SHA1_CTX ctx;
+	int error = 0;
+
+	HMAC_SHA1_Init(&ctx, key, SHA1_BLOCK_LENGTH);
+
+	/* Pseudo header. */
+	HMAC_SHA1_Update(&ctx, ph, ph->tap_len);
+
+	error = m_apply(m, moff, mlen, HMAC_SHA1_Update, &ctx);
+	if (error)
+		goto out;
+
+	HMAC_SHA1_Final(hash, &ctx);
+out:
+	bzero(&ctx, sizeof(ctx));
+	return (error);
+}
+
+/*
+ * Compute RFC5925+RFC5926 compliant AES-128-CMAC authentication MAC of
+ * a tcp segment.
+ */
+static int
+tcp_ao_cmac(uint32_t key[static AES_CMAC_KEY_LENGTH], struct pseudo *ph,
+    struct mbuf *m, int moff, int mlen, uint8_t hash[static AES_CMAC_DIGEST_LENGTH])
+{
+	AES_CMAC_CTX ctx;
+	int error = 0;
+
+	AES_CMAC_Init(&ctx);
+	AES_CMAC_SetKey(&ctx, key);
+
+	AES_CMAC_Update(&ctx, ph, ph->tap_len);
+
+	error = m_apply(m, moff, mlen, AES_CMAC_Update, &ctx);
+	if (error)
+		goto out;
+
+	AES_CMAC_Final(hash, &ctx);
+out:
+	bzero(&ctx, sizeof(ctx));
+	return (error);
+}
+
+/*
+ * Compute RFC2385 compliant MD5 authentication MAC of a tcp segment.
+ * Note that the SNE does not apply, the key comes last and the tcp options
+ * are not included.
+ */
+static int
+tcp_ao_md5(uint32_t key[static MD5_BLOCK_LENGTH], struct pseudo *ph,
+    struct mbuf *m, int moff, int mlen, uint8_t hash[static MD5_DIGEST_LENGTH])
+{
+	MD5_CTX ctx;
+	int error = 0, len;
+
+	MD5Init(&ctx);
+
+	len = ph->tap_len - sizeof(*ph->tap_sne) - sizeof(struct tcp_ao_thopt);
+	len += sizeof(struct tcphdr);
+	MD5Update(&ctx, &ph->tap, len;
+
+	error = m_apply(m, moff, mlen, AES_CMAC_Update, &ctx);
+	if (error)
+		goto out;
+
+	MD5Update(&ctx, key, MD5_BLOCK_LENGTH);
+
+	MD5Final(hash, &ctx);
+out:
+	bzero(%ctx, sizeof(ctx));
+	return (error);
+}
+


More information about the svn-src-user mailing list