Hi,

this is a second diff that brings support for AES-GCM and AES-GMAC
to IPsec/ESP.

PFKEY part is almost staitforward, except one tiny thing worth
mentioning: committee forgot to assign an ISAKMP id for the
ENCR_NULL_AUTH_AES_GMAC transform when they issued RFC 4543.
So... they assigned a different ID than the IKEv2 one :-)
The only place where it's needed is when we're doing key
exchange in isakmpd and I managed to keep mapping as simple
as possible:

    case IPSEC_ESP_AES_GMAC:
            ssa.sadb_sa_encrypt = SADB_X_EALG_AESGMAC;
            break;

IPSEC_ESP_AES_GMAC is 23 in fact.

ESP part gets a nice hack (esp_gcm_init_auth) that fakes an
authentication part of GCM from the encryption one.  Frankly,
I'd rather put this into the userland, but it won't be that
simple and contained.  Turned out, that it's much easier not
to touch SADB/PFKEY interface and deal with this at the ESP
initialization time.

Blocksize calculation code is an actual fix for stream ciphers
(RC4 being the only one, though it's disabled for IPsec).
Rationale is that ICV field (the one after the ciphertext) is
supposed to be 4-bytes aligned, therefore we have to pad to
4 bytes.

Length calculations are based on the fact that:
  crda->crd_len is the length of AAD
  crde->crd_len is the length of the payload (to be encr and auth'ed)

for AES-GMAC crde->crd_len is 0, but crda->crd_len includes
everything (SPI, SEQ, IV, padded payload).

Cheers,
Mike

Index: net/pfkeyv2.h
===================================================================
RCS file: /home/cvs/src/sys/net/pfkeyv2.h,v
retrieving revision 1.58
diff -u -p -r1.58 pfkeyv2.h
--- net/pfkeyv2.h       9 Jul 2010 16:58:06 -0000       1.58
+++ net/pfkeyv2.h       23 Aug 2010 16:56:23 -0000
@@ -297,6 +297,9 @@ struct sadb_x_tap {
 #define SADB_X_AALG_SHA2_384         6
 #define SADB_X_AALG_SHA2_512         7
 #define SADB_X_AALG_RIPEMD160HMAC    8
+#define SADB_X_AALG_AES128GMAC       9
+#define SADB_X_AALG_AES192GMAC       10
+#define SADB_X_AALG_AES256GMAC       11
 #define SADB_X_AALG_MD5              249
 #define SADB_X_AALG_SHA1             250
 #define SADB_AALG_MAX                250
@@ -315,6 +318,10 @@ struct sadb_x_tap {
 #define SADB_EALG_NULL        11
 #define SADB_X_EALG_AES       12
 #define SADB_X_EALG_AESCTR    13
+#define SADB_X_EALG_AESGCM8   18
+#define SADB_X_EALG_AESGCM12  19
+#define SADB_X_EALG_AESGCM16  20
+#define SADB_X_EALG_AESGMAC   21
 #define SADB_X_EALG_SKIPJACK  249
 #define SADB_EALG_MAX         249
 
Index: net/pfkeyv2_convert.c
===================================================================
RCS file: /home/cvs/src/sys/net/pfkeyv2_convert.c,v
retrieving revision 1.32
diff -u -p -r1.32 pfkeyv2_convert.c
--- net/pfkeyv2_convert.c       1 Jul 2010 02:09:45 -0000       1.32
+++ net/pfkeyv2_convert.c       23 Aug 2010 16:08:56 -0000
@@ -211,6 +211,18 @@ export_sa(void **p, struct tdb *tdb)
                        sadb_sa->sadb_sa_auth = SADB_X_AALG_SHA2_512;
                        break;
 
+               case CRYPTO_AES_128_GMAC:
+                       sadb_sa->sadb_sa_auth = SADB_X_AALG_AES128GMAC;
+                       break;
+
+               case CRYPTO_AES_192_GMAC:
+                       sadb_sa->sadb_sa_auth = SADB_X_AALG_AES192GMAC;
+                       break;
+
+               case CRYPTO_AES_256_GMAC:
+                       sadb_sa->sadb_sa_auth = SADB_X_AALG_AES256GMAC;
+                       break;
+
                case CRYPTO_MD5_KPDK:
                        sadb_sa->sadb_sa_auth = SADB_X_AALG_MD5;
                        break;
@@ -241,6 +253,14 @@ export_sa(void **p, struct tdb *tdb)
 
                case CRYPTO_AES_CTR:
                        sadb_sa->sadb_sa_encrypt = SADB_X_EALG_AESCTR;
+                       break;
+
+               case CRYPTO_AES_GCM_16:
+                       sadb_sa->sadb_sa_encrypt = SADB_X_EALG_AESGCM16;
+                       break;
+
+               case CRYPTO_AES_GMAC:
+                       sadb_sa->sadb_sa_encrypt = SADB_X_EALG_AESGMAC;
                        break;
 
                case CRYPTO_CAST_CBC:
Index: netinet/ip_esp.c
===================================================================
RCS file: /home/cvs/src/sys/netinet/ip_esp.c,v
retrieving revision 1.111
diff -u -p -r1.111 ip_esp.c
--- netinet/ip_esp.c    20 Jul 2010 15:36:03 -0000      1.111
+++ netinet/ip_esp.c    23 Aug 2010 17:15:02 -0000
@@ -82,6 +82,8 @@
 #define DPRINTF(x)
 #endif
 
+void esp_gcm_init_auth(struct ipsecinit *);
+
 struct espstat espstat;
 
 /*
@@ -131,6 +133,16 @@ esp_init(struct tdb *tdbp, struct xforms
                        txform = &enc_xform_aes_ctr;
                        break;
 
+               case SADB_X_EALG_AESGCM16:
+                       txform = &enc_xform_aes_gcm;
+                       esp_gcm_init_auth(ii);
+                       break;
+
+               case SADB_X_EALG_AESGMAC:
+                       txform = &enc_xform_aes_gmac;
+                       esp_gcm_init_auth(ii);
+                       break;
+
                case SADB_X_EALG_BLF:
                        txform = &enc_xform_blf;
                        break;
@@ -194,6 +206,18 @@ esp_init(struct tdb *tdbp, struct xforms
                        thash = &auth_hash_hmac_sha2_512_256;
                        break;
 
+               case SADB_X_AALG_AES128GMAC:
+                       thash = &auth_hash_gmac_aes_128;
+                       break;
+
+               case SADB_X_AALG_AES192GMAC:
+                       thash = &auth_hash_gmac_aes_192;
+                       break;
+
+               case SADB_X_AALG_AES256GMAC:
+                       thash = &auth_hash_gmac_aes_256;
+                       break;
+
                default:
                        DPRINTF(("esp_init(): unsupported authentication 
algorithm %d specified\n", ii->ii_authalg));
                        return EINVAL;
@@ -290,14 +314,13 @@ esp_input(struct mbuf *m, struct tdb *td
 {
        struct auth_hash *esph = (struct auth_hash *) tdb->tdb_authalgxform;
        struct enc_xform *espx = (struct enc_xform *) tdb->tdb_encalgxform;
+       struct cryptodesc *crde = NULL, *crda = NULL;
+       struct cryptop *crp;
        struct tdb_crypto *tc;
        int plen, alen, hlen;
        struct m_tag *mtag;
        u_int32_t btsx;
 
-       struct cryptodesc *crde = NULL, *crda = NULL;
-       struct cryptop *crp;
-
        /* Determine the ESP header length */
        if (tdb->tdb_flags & TDBF_NOREPLAY)
                hlen = sizeof(u_int32_t) + tdb->tdb_ivlen; /* "old" ESP */
@@ -424,13 +447,17 @@ esp_input(struct mbuf *m, struct tdb *td
 
                /* Authentication descriptor */
                crda->crd_skip = skip;
-               crda->crd_len = m->m_pkthdr.len - (skip + alen);
                crda->crd_inject = m->m_pkthdr.len - alen;
 
                crda->crd_alg = esph->type;
                crda->crd_key = tdb->tdb_amxkey;
                crda->crd_klen = tdb->tdb_amxkeylen * 8;
 
+               if (espx && espx->type == CRYPTO_AES_GCM_16)
+                       crda->crd_len = hlen - tdb->tdb_ivlen;
+               else
+                       crda->crd_len = m->m_pkthdr.len - (skip + alen);
+
                /* Copy the authenticator */
                if (mtag == NULL)
                        m_copydata(m, m->m_pkthdr.len - alen, alen, (caddr_t) 
(tc + 1));
@@ -456,7 +483,6 @@ esp_input(struct mbuf *m, struct tdb *td
        /* Decryption descriptor */
        if (espx) {
                crde->crd_skip = skip + hlen;
-               crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen);
                crde->crd_inject = skip + hlen - tdb->tdb_ivlen;
 
                if (tdb->tdb_flags & TDBF_HALFIV) {
@@ -474,6 +500,11 @@ esp_input(struct mbuf *m, struct tdb *td
                crde->crd_key = tdb->tdb_emxkey;
                crde->crd_klen = tdb->tdb_emxkeylen * 8;
                /* XXX Rounds ? */
+
+               if (crde->crd_alg == CRYPTO_AES_GMAC)
+                       crde->crd_len = 0;
+               else
+                       crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen);
        }
 
        if (mtag == NULL)
@@ -764,7 +795,7 @@ esp_output(struct mbuf *m, struct tdb *t
 
        rlen = m->m_pkthdr.len - skip; /* Raw payload length. */
        if (espx)
-               blks = espx->blocksize;
+               blks = MAX(espx->blocksize, 4);
        else
                blks = 4; /* If no encryption, we have to be 4-byte aligned. */
 
@@ -926,7 +963,6 @@ esp_output(struct mbuf *m, struct tdb *t
 
                /* Encryption descriptor. */
                crde->crd_skip = skip + hlen;
-               crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen);
                crde->crd_flags = CRD_F_ENCRYPT;
                crde->crd_inject = skip + hlen - tdb->tdb_ivlen;
 
@@ -950,6 +986,11 @@ esp_output(struct mbuf *m, struct tdb *t
                crde->crd_key = tdb->tdb_emxkey;
                crde->crd_klen = tdb->tdb_emxkeylen * 8;
                /* XXX Rounds ? */
+
+               if (crde->crd_alg == CRYPTO_AES_GMAC)
+                       crde->crd_len = 0;
+               else
+                       crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen);
        } else
                crda = crp->crp_desc;
 
@@ -979,13 +1020,17 @@ esp_output(struct mbuf *m, struct tdb *t
        if (esph) {
                /* Authentication descriptor. */
                crda->crd_skip = skip;
-               crda->crd_len = m->m_pkthdr.len - (skip + alen);
                crda->crd_inject = m->m_pkthdr.len - alen;
 
                /* Authentication operation. */
                crda->crd_alg = esph->type;
                crda->crd_key = tdb->tdb_amxkey;
                crda->crd_klen = tdb->tdb_amxkeylen * 8;
+
+               if (espx && espx->type == CRYPTO_AES_GCM_16)
+                       crda->crd_len = hlen - tdb->tdb_ivlen;
+               else
+                       crda->crd_len = m->m_pkthdr.len - (skip + alen);
        }
 
        if ((tdb->tdb_flags & TDBF_SKIPCRYPTO) == 0)
@@ -1199,4 +1244,23 @@ m_pad(struct mbuf *m, int n)
        m->m_pkthdr.len += pad;
 
        return retval;
+}
+
+void
+esp_gcm_init_auth(struct ipsecinit *ii)
+{
+       switch (ii->ii_enckeylen) {
+       case 20:
+               ii->ii_authalg = SADB_X_AALG_AES128GMAC;
+               break;
+       case 28:
+               ii->ii_authalg = SADB_X_AALG_AES192GMAC;
+               break;
+       case 36:
+               ii->ii_authalg = SADB_X_AALG_AES256GMAC;
+               break;
+       }
+
+       ii->ii_authkeylen = ii->ii_enckeylen;
+       ii->ii_authkey = ii->ii_enckey;
 }

Reply via email to