CCM support.
authorDr. Stephen Henson <steve@openssl.org>
Fri, 31 Jul 2015 15:54:35 +0000 (16:54 +0100)
committerDr. Stephen Henson <steve@openssl.org>
Fri, 14 Aug 2015 05:56:11 +0000 (06:56 +0100)
Reviewed-by: Tim Hudson <tjh@openssl.org>
crypto/evp/e_aes.c
include/openssl/evp.h
include/openssl/ssl.h
ssl/record/rec_layer_d1.c
ssl/record/rec_layer_s3.c
ssl/record/ssl3_record.c
ssl/ssl_algs.c
ssl/ssl_ciph.c
ssl/ssl_locl.h
ssl/t1_enc.c

index f8365a2..b02cf6e 100644 (file)
@@ -110,6 +110,7 @@ typedef struct {
     int tag_set;                /* Set if tag is valid */
     int len_set;                /* Set if message length set */
     int L, M;                   /* L and M parameters from RFC3610 */
+    int tls_aad_len;            /* TLS AAD length */
     CCM128_CONTEXT ccm;
     ccm128_f str;
 } EVP_AES_CCM_CTX;
@@ -1853,6 +1854,34 @@ static int aes_ccm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
         cctx->M = 12;
         cctx->tag_set = 0;
         cctx->len_set = 0;
+        cctx->tls_aad_len = -1;
+        return 1;
+
+    case EVP_CTRL_AEAD_TLS1_AAD:
+        /* Save the AAD for later use */
+        if (arg != EVP_AEAD_TLS1_AAD_LEN)
+            return 0;
+        memcpy(c->buf, ptr, arg);
+        cctx->tls_aad_len = arg;
+        {
+            uint16_t len = c->buf[arg - 2] << 8 | c->buf[arg - 1];
+            /* Correct length for explicit IV */
+            len -= EVP_CCM_TLS_EXPLICIT_IV_LEN;
+            /* If decrypting correct for tag too */
+            if (!c->encrypt)
+                len -= cctx->M;
+            c->buf[arg - 2] = len >> 8;
+            c->buf[arg - 1] = len & 0xff;
+        }
+        /* Extra padding: tag appended to record */
+        return cctx->M;
+
+    case EVP_CTRL_CCM_SET_IV_FIXED:
+        /* Sanity check length */
+        if (arg != EVP_CCM_TLS_FIXED_IV_LEN)
+            return 0;
+        /* Just copy to first part of IV */
+        memcpy(c->iv, ptr, arg);
         return 1;
 
     case EVP_CTRL_AEAD_SET_IVLEN:
@@ -1945,14 +1974,66 @@ static int aes_ccm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
     return 1;
 }
 
+static int aes_ccm_tls_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+                              const unsigned char *in, size_t len)
+{
+    EVP_AES_CCM_CTX *cctx = ctx->cipher_data;
+    CCM128_CONTEXT *ccm = &cctx->ccm;
+    /* Encrypt/decrypt must be performed in place */
+    if (out != in || len < (EVP_CCM_TLS_EXPLICIT_IV_LEN + (size_t)cctx->M))
+        return -1;
+    /* If encrypting set explicit IV from sequence number (start of AAD) */
+    if (ctx->encrypt)
+        memcpy(out, ctx->buf, EVP_CCM_TLS_EXPLICIT_IV_LEN);
+    /* Get rest of IV from explicit IV */
+    memcpy(ctx->iv + EVP_CCM_TLS_FIXED_IV_LEN, in, EVP_CCM_TLS_EXPLICIT_IV_LEN);
+    /* Correct length value */
+    len -= EVP_CCM_TLS_EXPLICIT_IV_LEN + cctx->M;
+    if (CRYPTO_ccm128_setiv(ccm, ctx->iv, 15 - cctx->L, len))
+            return -1;
+    /* Use saved AAD */
+    CRYPTO_ccm128_aad(ccm, ctx->buf, cctx->tls_aad_len);
+    /* Fix buffer to point to payload */
+    in += EVP_CCM_TLS_EXPLICIT_IV_LEN;
+    out += EVP_CCM_TLS_EXPLICIT_IV_LEN;
+    if (ctx->encrypt) {
+        if (cctx->str ? CRYPTO_ccm128_encrypt_ccm64(ccm, in, out, len,
+                                                    cctx->str) :
+            CRYPTO_ccm128_encrypt(ccm, in, out, len))
+            return -1;
+        if (!CRYPTO_ccm128_tag(ccm, out + len, cctx->M))
+            return -1;
+        return len + EVP_CCM_TLS_EXPLICIT_IV_LEN + cctx->M;
+    } else {
+        if (cctx->str ? !CRYPTO_ccm128_decrypt_ccm64(ccm, in, out, len,
+                                                     cctx->str) :
+            !CRYPTO_ccm128_decrypt(ccm, in, out, len)) {
+            unsigned char tag[16];
+            if (CRYPTO_ccm128_tag(ccm, tag, cctx->M)) {
+                if (!CRYPTO_memcmp(tag, in + len, cctx->M))
+                    return len;
+            }
+        }
+        OPENSSL_cleanse(out, len);
+        return -1;
+    }
+}
+
 static int aes_ccm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
                           const unsigned char *in, size_t len)
 {
     EVP_AES_CCM_CTX *cctx = ctx->cipher_data;
     CCM128_CONTEXT *ccm = &cctx->ccm;
     /* If not set up, return error */
-    if (!cctx->iv_set && !cctx->key_set)
+    if (!cctx->key_set)
+        return -1;
+
+    if (cctx->tls_aad_len >= 0)
+        return aes_ccm_tls_cipher(ctx, out, in, len);
+
+    if (!cctx->iv_set)
         return -1;
+
     if (!ctx->encrypt && !cctx->tag_set)
         return -1;
     if (!out) {
@@ -2007,9 +2088,12 @@ static int aes_ccm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
 
 # define aes_ccm_cleanup NULL
 
-BLOCK_CIPHER_custom(NID_aes, 128, 1, 12, ccm, CCM, CUSTOM_FLAGS)
-    BLOCK_CIPHER_custom(NID_aes, 192, 1, 12, ccm, CCM, CUSTOM_FLAGS)
-    BLOCK_CIPHER_custom(NID_aes, 256, 1, 12, ccm, CCM, CUSTOM_FLAGS)
+BLOCK_CIPHER_custom(NID_aes, 128, 1, 12, ccm, CCM,
+                    EVP_CIPH_FLAG_AEAD_CIPHER | CUSTOM_FLAGS)
+    BLOCK_CIPHER_custom(NID_aes, 192, 1, 12, ccm, CCM,
+                        EVP_CIPH_FLAG_AEAD_CIPHER | CUSTOM_FLAGS)
+    BLOCK_CIPHER_custom(NID_aes, 256, 1, 12, ccm, CCM,
+                        EVP_CIPH_FLAG_AEAD_CIPHER | CUSTOM_FLAGS)
 
 typedef struct {
     union {
index dff81b0..ddefbf6 100644 (file)
@@ -399,14 +399,16 @@ struct evp_cipher_st {
 # define         EVP_CTRL_AEAD_SET_IVLEN         0x9
 # define         EVP_CTRL_AEAD_GET_TAG           0x10
 # define         EVP_CTRL_AEAD_SET_TAG           0x11
+# define         EVP_CTRL_AEAD_SET_IV_FIXED      0x12
 # define         EVP_CTRL_GCM_SET_IVLEN          EVP_CTRL_AEAD_SET_IVLEN
 # define         EVP_CTRL_GCM_GET_TAG            EVP_CTRL_AEAD_GET_TAG
 # define         EVP_CTRL_GCM_SET_TAG            EVP_CTRL_AEAD_SET_TAG
-# define         EVP_CTRL_GCM_SET_IV_FIXED       0x12
+# define         EVP_CTRL_GCM_SET_IV_FIXED       EVP_CTRL_AEAD_SET_IV_FIXED
 # define         EVP_CTRL_GCM_IV_GEN             0x13
 # define         EVP_CTRL_CCM_SET_IVLEN          EVP_CTRL_AEAD_SET_IVLEN
 # define         EVP_CTRL_CCM_GET_TAG            EVP_CTRL_AEAD_GET_TAG
 # define         EVP_CTRL_CCM_SET_TAG            EVP_CTRL_AEAD_SET_TAG
+# define         EVP_CTRL_CCM_SET_IV_FIXED       EVP_CTRL_AEAD_SET_IV_FIXED
 # define         EVP_CTRL_CCM_SET_L              0x14
 # define         EVP_CTRL_CCM_SET_MSGLEN         0x15
 /*
@@ -443,6 +445,12 @@ typedef struct {
 /* Length of tag for TLS */
 # define EVP_GCM_TLS_TAG_LEN                             16
 
+/* CCM TLS constants */
+/* Length of fixed part of IV derived from PRF */
+# define EVP_CCM_TLS_FIXED_IV_LEN                        4
+/* Length of explicit part of IV part of TLS records */
+# define EVP_CCM_TLS_EXPLICIT_IV_LEN                     8
+
 typedef struct evp_cipher_info_st {
     const EVP_CIPHER *cipher;
     unsigned char iv[EVP_MAX_IV_LENGTH];
index 28c2fb9..d2512b8 100644 (file)
@@ -245,6 +245,7 @@ extern "C" {
 # define SSL_TXT_AES256          "AES256"
 # define SSL_TXT_AES             "AES"
 # define SSL_TXT_AES_GCM         "AESGCM"
+# define SSL_TXT_AES_CCM         "AESCCM"
 # define SSL_TXT_CAMELLIA128     "CAMELLIA128"
 # define SSL_TXT_CAMELLIA256     "CAMELLIA256"
 # define SSL_TXT_CAMELLIA        "CAMELLIA"
index 3da4f11..74796be 100644 (file)
@@ -1120,6 +1120,8 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf,
         /* Need explicit part of IV for GCM mode */
         else if (mode == EVP_CIPH_GCM_MODE)
             eivlen = EVP_GCM_TLS_EXPLICIT_IV_LEN;
+        else if (mode == EVP_CIPH_CCM_MODE)
+            eivlen = EVP_CCM_TLS_EXPLICIT_IV_LEN;
         else
             eivlen = 0;
     } else
index 8a9e303..5b28663 100644 (file)
@@ -799,6 +799,8 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
         /* Need explicit part of IV for GCM mode */
         else if (mode == EVP_CIPH_GCM_MODE)
             eivlen = EVP_GCM_TLS_EXPLICIT_IV_LEN;
+        else if (mode == EVP_CIPH_CCM_MODE)
+            eivlen = EVP_CCM_TLS_EXPLICIT_IV_LEN;
         else
             eivlen = 0;
     } else
index 1865f24..1fa1710 100644 (file)
@@ -764,10 +764,16 @@ int tls1_enc(SSL *s, int send)
             ? (i < 0)
             : (i == 0))
             return -1;          /* AEAD can fail to verify MAC */
-        if (EVP_CIPHER_mode(enc) == EVP_CIPH_GCM_MODE && !send) {
-            rec->data += EVP_GCM_TLS_EXPLICIT_IV_LEN;
-            rec->input += EVP_GCM_TLS_EXPLICIT_IV_LEN;
-            rec->length -= EVP_GCM_TLS_EXPLICIT_IV_LEN;
+        if (send == 0) {
+            if (EVP_CIPHER_mode(enc) == EVP_CIPH_GCM_MODE) {
+                rec->data += EVP_GCM_TLS_EXPLICIT_IV_LEN;
+                rec->input += EVP_GCM_TLS_EXPLICIT_IV_LEN;
+                rec->length -= EVP_GCM_TLS_EXPLICIT_IV_LEN;
+            } else if (EVP_CIPHER_mode(enc) == EVP_CIPH_CCM_MODE) {
+                rec->data += EVP_CCM_TLS_EXPLICIT_IV_LEN;
+                rec->input += EVP_CCM_TLS_EXPLICIT_IV_LEN;
+                rec->length -= EVP_CCM_TLS_EXPLICIT_IV_LEN;
+            }
         }
 
         ret = 1;
index ba9fc48..f4827fd 100644 (file)
@@ -91,6 +91,8 @@ int SSL_library_init(void)
     EVP_add_cipher(EVP_aes_256_cbc());
     EVP_add_cipher(EVP_aes_128_gcm());
     EVP_add_cipher(EVP_aes_256_gcm());
+    EVP_add_cipher(EVP_aes_128_ccm());
+    EVP_add_cipher(EVP_aes_256_ccm());
     EVP_add_cipher(EVP_aes_128_cbc_hmac_sha1());
     EVP_add_cipher(EVP_aes_256_cbc_hmac_sha1());
     EVP_add_cipher(EVP_aes_128_cbc_hmac_sha256());
index 08a95f9..7f2970b 100644 (file)
 #define SSL_ENC_SEED_IDX        11
 #define SSL_ENC_AES128GCM_IDX   12
 #define SSL_ENC_AES256GCM_IDX   13
-#define SSL_ENC_NUM_IDX         14
+#define SSL_ENC_AES128CCM_IDX   14
+#define SSL_ENC_AES256CCM_IDX   15
+#define SSL_ENC_NUM_IDX         16
 
 /* NB: make sure indices in these tables match values above */
 
@@ -188,7 +190,9 @@ static const ssl_cipher_table ssl_cipher_table_cipher[SSL_ENC_NUM_IDX] = {
     {SSL_eGOST2814789CNT, NID_gost89_cnt}, /* SSL_ENC_GOST89_IDX 10 */
     {SSL_SEED, NID_seed_cbc},   /* SSL_ENC_SEED_IDX 11 */
     {SSL_AES128GCM, NID_aes_128_gcm}, /* SSL_ENC_AES128GCM_IDX 12 */
-    {SSL_AES256GCM, NID_aes_256_gcm} /* SSL_ENC_AES256GCM_IDX 13 */
+    {SSL_AES256GCM, NID_aes_256_gcm}, /* SSL_ENC_AES256GCM_IDX 13 */
+    {SSL_AES128CCM, NID_aes_128_ccm}, /* SSL_ENC_AES128CCM_IDX 14 */
+    {SSL_AES256CCM, NID_aes_256_ccm} /* SSL_ENC_AES256CCM_IDX 15 */
 };
 
 static const EVP_CIPHER *ssl_cipher_methods[SSL_ENC_NUM_IDX] = {
@@ -355,13 +359,15 @@ static const SSL_CIPHER cipher_aliases[] = {
     {0, SSL_TXT_IDEA, 0, 0, 0, SSL_IDEA, 0, 0, 0, 0, 0, 0},
     {0, SSL_TXT_SEED, 0, 0, 0, SSL_SEED, 0, 0, 0, 0, 0, 0},
     {0, SSL_TXT_eNULL, 0, 0, 0, SSL_eNULL, 0, 0, 0, 0, 0, 0},
-    {0, SSL_TXT_AES128, 0, 0, 0, SSL_AES128 | SSL_AES128GCM, 0, 0, 0, 0, 0,
-     0},
-    {0, SSL_TXT_AES256, 0, 0, 0, SSL_AES256 | SSL_AES256GCM, 0, 0, 0, 0, 0,
-     0},
+    {0, SSL_TXT_AES128, 0, 0, 0, SSL_AES128 | SSL_AES128GCM | SSL_AES128CCM, 0,
+     0, 0, 0, 0, 0},
+    {0, SSL_TXT_AES256, 0, 0, 0, SSL_AES256 | SSL_AES256GCM | SSL_AES256CCM, 0,
+     0, 0, 0, 0, 0},
     {0, SSL_TXT_AES, 0, 0, 0, SSL_AES, 0, 0, 0, 0, 0, 0},
     {0, SSL_TXT_AES_GCM, 0, 0, 0, SSL_AES128GCM | SSL_AES256GCM, 0, 0, 0, 0,
      0, 0},
+    {0, SSL_TXT_AES_CCM, 0, 0, 0, SSL_AES128CCM | SSL_AES256CCM, 0, 0, 0, 0,
+     0, 0},
     {0, SSL_TXT_CAMELLIA128, 0, 0, 0, SSL_CAMELLIA128, 0, 0, 0, 0, 0, 0},
     {0, SSL_TXT_CAMELLIA256, 0, 0, 0, SSL_CAMELLIA256, 0, 0, 0, 0, 0, 0},
     {0, SSL_TXT_CAMELLIA, 0, 0, 0, SSL_CAMELLIA128 | SSL_CAMELLIA256, 0, 0, 0,
@@ -1709,6 +1715,12 @@ char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len)
     case SSL_AES256GCM:
         enc = "AESGCM(256)";
         break;
+    case SSL_AES128CCM:
+        enc = "AESCCM(128)";
+        break;
+    case SSL_AES256CCM:
+        enc = "AESCCM(256)";
+        break;
     case SSL_CAMELLIA128:
         enc = "Camellia(128)";
         break;
index 63b547a..b30a635 100644 (file)
 # define SSL_SEED                0x00000800L
 # define SSL_AES128GCM           0x00001000L
 # define SSL_AES256GCM           0x00002000L
+# define SSL_AES128CCM           0x00004000L
+# define SSL_AES256CCM           0x00008000L
 
-# define SSL_AES                 (SSL_AES128|SSL_AES256|SSL_AES128GCM|SSL_AES256GCM)
+# define SSL_AES                 (SSL_AES128|SSL_AES256|SSL_AES128GCM|SSL_AES256GCM|SSL_AES128CCM|SSL_AES256CCM)
 # define SSL_CAMELLIA            (SSL_CAMELLIA128|SSL_CAMELLIA256)
 
 /* Bits for algorithm_mac (symmetric authentication) */
index 9942bb4..87de2fe 100644 (file)
@@ -422,9 +422,11 @@ int tls1_change_cipher_state(SSL *s, int which)
     j = is_export ? (cl < SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher) ?
                      cl : SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher)) : cl;
     /* Was j=(exp)?5:EVP_CIPHER_key_length(c); */
-    /* If GCM mode only part of IV comes from PRF */
+    /* If GCM/CCM mode only part of IV comes from PRF */
     if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE)
         k = EVP_GCM_TLS_FIXED_IV_LEN;
+    else if (EVP_CIPHER_mode(c) == EVP_CIPH_CCM_MODE)
+        k = EVP_CCM_TLS_FIXED_IV_LEN;
     else
         k = EVP_CIPHER_iv_length(c);
     if ((which == SSL3_CHANGE_CIPHER_CLIENT_WRITE) ||
@@ -506,6 +508,16 @@ int tls1_change_cipher_state(SSL *s, int which)
             SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR);
             goto err2;
         }
+    } else if (EVP_CIPHER_mode(c) == EVP_CIPH_CCM_MODE) {
+        int taglen = 16;
+        if (!EVP_CipherInit_ex(dd, c, NULL, NULL, NULL, (which & SSL3_CC_WRITE))
+            || !EVP_CIPHER_CTX_ctrl(dd, EVP_CTRL_AEAD_SET_IVLEN, 12, NULL)
+            || !EVP_CIPHER_CTX_ctrl(dd, EVP_CTRL_AEAD_SET_TAG, taglen, NULL)
+            || !EVP_CIPHER_CTX_ctrl(dd, EVP_CTRL_CCM_SET_IV_FIXED, k, iv)
+            || !EVP_CipherInit_ex(dd, NULL, NULL, key, NULL, -1)) {
+            SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR);
+            goto err2;
+        }
     } else {
         if (!EVP_CipherInit_ex(dd, c, NULL, key, iv, (which & SSL3_CC_WRITE))) {
             SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR);