Refs #4375 -- integrate wycheproof AES CCM tests (#4379)

* Refs #4375 -- integrate wycheproof AES CCM tests

* Skip these tests if we don't have CCM support
diff --git a/docs/hazmat/primitives/aead.rst b/docs/hazmat/primitives/aead.rst
index a54cc6f..06fecc5 100644
--- a/docs/hazmat/primitives/aead.rst
+++ b/docs/hazmat/primitives/aead.rst
@@ -169,7 +169,7 @@
     :param int tag_length: The length of the authentication tag. This
         defaults to 16 bytes and it is **strongly** recommended that you
         do not make it shorter unless absolutely necessary. Valid tag
-        lengths are 4, 6, 8, 12, 14, and 16.
+        lengths are 4, 6, 8, 10, 12, 14, and 16.
 
     :raises cryptography.exceptions.UnsupportedAlgorithm: If the version of
         OpenSSL does not support AES-CCM.
diff --git a/src/cryptography/hazmat/primitives/ciphers/aead.py b/src/cryptography/hazmat/primitives/ciphers/aead.py
index e519765..16899d0 100644
--- a/src/cryptography/hazmat/primitives/ciphers/aead.py
+++ b/src/cryptography/hazmat/primitives/ciphers/aead.py
@@ -75,7 +75,7 @@
         if not isinstance(tag_length, int):
             raise TypeError("tag_length must be an integer")
 
-        if tag_length not in (4, 6, 8, 12, 14, 16):
+        if tag_length not in (4, 6, 8, 10, 12, 14, 16):
             raise ValueError("Invalid tag_length")
 
         self._tag_length = tag_length
diff --git a/tests/wycheproof/test_aes.py b/tests/wycheproof/test_aes.py
index a3d7512..55e4545 100644
--- a/tests/wycheproof/test_aes.py
+++ b/tests/wycheproof/test_aes.py
@@ -14,7 +14,9 @@
 from cryptography.hazmat.primitives.ciphers import (
     Cipher, algorithms, modes
 )
-from cryptography.hazmat.primitives.ciphers.aead import AESGCM
+from cryptography.hazmat.primitives.ciphers.aead import AESCCM, AESGCM
+
+from ..hazmat.primitives.test_aead import _aead_supported
 
 
 @pytest.mark.requires_backend_interface(interface=CipherBackend)
@@ -104,3 +106,39 @@
     else:
         with pytest.raises(InvalidTag):
             aesgcm.decrypt(iv, ct + tag, aad)
+
+
+@pytest.mark.skipif(
+    not _aead_supported(AESCCM),
+    reason="Requires OpenSSL with AES-CCM support",
+)
+@pytest.mark.requires_backend_interface(interface=CipherBackend)
+@pytest.mark.wycheproof_tests("aes_ccm_test.json")
+def test_aes_ccm_aead_api(backend, wycheproof):
+    key = binascii.unhexlify(wycheproof.testcase["key"])
+    iv = binascii.unhexlify(wycheproof.testcase["iv"])
+    aad = binascii.unhexlify(wycheproof.testcase["aad"])
+    msg = binascii.unhexlify(wycheproof.testcase["msg"])
+    ct = binascii.unhexlify(wycheproof.testcase["ct"])
+    tag = binascii.unhexlify(wycheproof.testcase["tag"])
+
+    if (
+        wycheproof.invalid and
+        wycheproof.testcase["comment"] == "Invalid tag size"
+    ):
+        with pytest.raises(ValueError):
+            AESCCM(key, tag_length=wycheproof.testgroup["tagSize"] // 8)
+        return
+
+    aesccm = AESCCM(key, tag_length=wycheproof.testgroup["tagSize"] // 8)
+    if wycheproof.valid or wycheproof.acceptable:
+        computed_ct = aesccm.encrypt(iv, msg, aad)
+        assert computed_ct == ct + tag
+        computed_msg = aesccm.decrypt(iv, ct + tag, aad)
+        assert computed_msg == msg
+    elif not 7 <= len(iv) <= 13:
+        with pytest.raises(ValueError):
+            aesccm.decrypt(iv, ct + tag, aad)
+    else:
+        with pytest.raises(InvalidTag):
+            aesccm.decrypt(iv, ct + tag, aad)