AEAD (for AES128-GCM): is it necessary to add a zero-length AAD? In an implementation of AEAD_AES_128_GCM, if the AAD is defined as a "zero-length octet sequence", is it necessary to call the encryption code that adds an AAD at all? In particular, does an OpenSSL/LibreSSL libcrypto client need the EVP_En/DecryptUpdate invocation that adds the AAD, if its length is 0?

I'm working on an implementation of RFC 8188, a protocol for encrypting HTTP messages with AEAD_AES_128_GCM, which has this to say:

   The additional data passed to each invocation of AEAD_AES_128_GCM is
   a zero-length octet sequence.


Currently my test code (just in a mockup stage) has this:

static const unsigned char *aad = (const void *)&amp;aad;
static const int aad_len = 0;

#if 0
    /* XXX not sure if this is necessary, examples work with &amp; without */
    if (EVP_DecryptUpdate(&amp;ctx, NULL, &amp;len, aad, aad_len) != 1) {
        ERR("decryption: adding aad");
        return -1;
    }
#endif


The resulting code produces the expected decryptions and intermediate values for the examples in chapter 3 of the RFC. As you can see, this part is #if 0-d out, so in fact nothing is done to add an AAD.

Since this may seem like a remarkably silly question (already I'm pre-emptively embarrassed), let me explain why I'm asking:


The RFC has all of two examples, both of which decrypt ciphertext to "I am the walrus" (with two different record sizes). So the "it works" result may be a lucky accident of sparse test data.
Since the RFC goes to the trouble of saying "zero-length octet sequence", rather than something like "there is no AAD", it feels like there might be a reason for putting it that way.
An assumption on my part, a crypto layman, that "it's zero-length so I don't have to do anything" feels like the sort of thing that leads to errors and insecurity in code that uses cryptography. Operations on zero-length structures don't always mean the same thing as "do nothing" (consider SHA hashes of the empty string).


So I thought I'd ask others if there might be more going on here than meets the eye.
AES-GCM does not support ‘no AAD’ as distinct from ‘zero-length AAD’.  See NIST SP800-38D for details of how it works internally: the AAD is padded with zeros so it is a multiple of 128 bits long, and the length is hashed in at the end.  If the AAD is zero-length, then zero bits of padding are added and no time is spent hashing any AAD or AAD padding.


  
  Let $u = 128\cdot\lceil\operatorname{len}(C)/128\rceil - \operatorname{len}(C)$ and let $v = 128\cdot\lceil\operatorname{len}(A)/128\rceil - \operatorname{len}(A)$.
  Define a block, $S$, as follows: $$S = \operatorname{GHASH}_H(A \mathbin\| \mathtt 0^v \mathbin\| C \mathbin\| \mathtt 0^u \mathbin\| [\operatorname{len}(A)]_{64} \mathbin\| [\operatorname{len}(C)]_{64}).$$
  
  
  …
  
  In Steps 4 and 5, the AAD and the ciphertext are each appended with the minimum number of ‘$\mathtt 0$’ bits, possibly none, so that the bit lengths of the resulting strings are multiples of the block size.
  
  —NIST SP800-90A, §7.1 ‘Algorithm for the Authenticated Encryption Function’, p. 15 (emphasis added)


Note that if the AAD $A$ is empty, then $\operatorname{len}(A) = \lceil0/128\rceil = 0$, so $\lceil\operatorname{len}(A)/128\rceil = 0$, and thus the number of ‘$\mathtt 0$’ bits appended is $$v = 128\cdot\lceil\operatorname{len}(A)/128\rceil - \operatorname{len}(A) = 128\cdot0 - 0 = 0.$$  In other words, if $A$ is empty, then the prefix $A \mathbin\| \mathtt 0^v$ is also empty.

But it is a good intuition to wonder whether ‘no AAD’ and ‘zero-length AAD’ are distinct!  There are many applications that do make such distinctions, often to the advantage of adversaries or at least to the frustration of legitimate users.