]> git.saurik.com Git - apple/security.git/blobdiff - libsecurity_ssl/lib/symCipher.c
Security-55471.14.8.tar.gz
[apple/security.git] / libsecurity_ssl / lib / symCipher.c
index 45d9ef8efb9fd5c47854351c11d2451375bd1222..aab1ec059394bdea6b0615b32be00e2dbd70ae1d 100644 (file)
  */
 
 /*
- * symCipher.c - CDSA-based symmetric cipher module
+ * symCipher.c - CommonCrypto-based symmetric cipher module
  */
 
-#include "sslContext.h"
-#include "cryptType.h"
+/* THIS FILE CONTAINS KERNEL CODE */
+
+#include "sslBuildFlags.h"
 #include "sslDebug.h"
 #include "sslMemory.h"
-#include <CommonCrypto/CommonCryptor.h>
 #include "symCipher.h"
+#include "cipherSpecs.h"
+#include "SSLRecordInternal.h"
+
+#ifdef KERNEL
+
+#include <corecrypto/ccaes.h>
+#include <corecrypto/ccdes.h>
+#include <corecrypto/ccmode.h>
+
+#include <AssertMacros.h>
+
+struct SymCipherContext {
+    const struct ccmode_cbc *cbc;
+    cccbc_ctx u[]; /* this will have the key and iv */
+};
+
+/* Macros for accessing the content of a SymCipherContext */
+/*
+ SymCipherContext looks like this in memory:
+ {
+    const struct ccmode_cbc *cbc;
+    cccbc_ctx key[n];
+    cccbc_iv  iv[m];
+ }
+ cccbc_ctx and cccbc_iv are typedef-ined as aligned opaque struct, the actual contexts are arrays
+ of those types normally declared with a cc_ctx_decl macro.
+ The cc_ctx_n macros gives the number of elements in those arrays that are needed to store the
+ contexts.
+ The size of the context depends on the actual cbc implementation used.
+*/
+
+
+/* CTX_SIZE: Total size of the SymCipherContext struct for a cbc implementation */
+static inline
+size_t CTX_SIZE(const struct ccmode_cbc *cbc)
+{
+#ifdef __CC_HAS_FIX_FOR_11468135__
+    return (sizeof(SymCipherContext) + (sizeof(cccbc_ctx) * (cc_ctx_n(cccbc_ctx, cbc->size) + cc_ctx_n(cccbc_iv, cbc->block_size))));
+#else
+    /* This is approximate, but will work in that case, this code will go away after we transition */
+    return (sizeof(SymCipherContext) + sizeof(cccbc_ctx) + cbc->size);
+#endif
+}
+
+/* CTX_KEY: Address of the key context in the SymCipherContext struct */
+static inline
+cccbc_ctx *CTX_KEY(struct SymCipherContext *ctx)
+{
+    return &ctx->u[0];
+}
+
+
+/* CTX_IV: Address of the iv context in the SymCipherContext struct */
+#ifdef __CC_HAS_FIX_FOR_11468135__
+static inline
+cccbc_iv *CTX_IV(struct SymCipherContext *ctx)
+{
+    return (cccbc_iv *)&ctx->u[cc_ctx_n(cccbc_ctx, ctx->cbc->size)];
+}
+#endif
+
+static
+const void *ccmode(SSL_CipherAlgorithm alg, int enc)
+{
+    switch(alg) {
+        case SSL_CipherAlgorithmAES_128_CBC:
+        case SSL_CipherAlgorithmAES_256_CBC:
+            return enc?ccaes_cbc_encrypt_mode():ccaes_cbc_decrypt_mode();
+        case SSL_CipherAlgorithm3DES_CBC:
+            return enc?ccdes3_cbc_encrypt_mode():ccdes3_cbc_decrypt_mode();
+        case SSL_CipherAlgorithmAES_128_GCM:
+        case SSL_CipherAlgorithmAES_256_GCM:
+        case SSL_CipherAlgorithmRC4_128:
+            /* TODO: we should do RC4 for TLS, but we dont need it for DTLS */
+        default:
+            check(0);
+            return NULL; /* This will cause CCCryptorCreate to return an error */
+    }
+}
+
+static
+int CCSymmInit(
+    const SSLSymmetricCipherParams *params,
+    int encrypting,
+    uint8_t *key,
+    uint8_t* iv,
+    SymCipherContext *cipherCtx)
+{
+    check(cipherCtx!=NULL);
+    check(params);
+    SymCipherContext ctx = *cipherCtx;
+
+       /*
+        * Cook up a cccbx_ctx object. Assumes:
+        *              cipherCtx->symCipher.keyAlg
+        *              cipherCtx->encrypting
+        *              key (raw key bytes)
+        *              iv (raw bytes)
+        * On successful exit:
+        *              Resulting ccmode --> cipherCtx
+        */
+
+    /* FIXME: this should not be needed as long as CCSymFinish is called */
+       if(ctx) {
+        sslFree(ctx);
+        ctx = NULL;
+       }
+
+    const struct ccmode_cbc *cbc = ccmode(params->keyAlg, encrypting);
+
+    ctx = sslMalloc(CTX_SIZE(cbc));
+
+    if(ctx==NULL) {
+        sslErrorLog("CCSymmInit: Can't allocate context\n");
+        return errSSLRecordInternal;
+    }
+
+    ctx->cbc = cbc;
+
+#ifdef __CC_HAS_FIX_FOR_11468135__
+    cccbc_init(cbc, CTX_KEY(ctx), params->keySize, key);
+    cccbc_set_iv(cbc, CTX_IV(ctx), iv);
+#else
+    cccbc_init(cbc, CTX_KEY(ctx), params->keySize, key, iv);
+#endif
+
+    *cipherCtx = ctx;
+       return 0;
+}
+
+/* same for en/decrypt */
+static
+int CCSymmEncryptDecrypt(
+                         const uint8_t *src,
+                         uint8_t *dest,
+                         size_t len,
+                         SymCipherContext cipherCtx)
+{
+
+       ASSERT(cipherCtx != NULL);
+    ASSERT(cipherCtx->cbc != NULL);
+
+       if(cipherCtx == NULL || cipherCtx->cbc == NULL) {
+               sslErrorLog("CCSymmEncryptDecrypt: NULL cipherCtx\n");
+               return errSSLRecordInternal;
+       }
+
+    ASSERT((len%cipherCtx->cbc->block_size)==0);
+
+    if(len%cipherCtx->cbc->block_size) {
+        sslErrorLog("CCSymmEncryptDecrypt: Invalid size\n");
+        return errSSLRecordInternal;
+    }
+
+    unsigned long nblocks = len/cipherCtx->cbc->block_size;
+
+#ifdef __CC_HAS_FIX_FOR_11468135__
+    cccbc_update(cipherCtx->cbc, CTX_KEY(cipherCtx), CTX_IV(cipherCtx), nblocks, src, dest);
+#else
+    cipherCtx->cbc->cbc(CTX_KEY(cipherCtx), nblocks, src, dest);
+#endif
+       return 0;
+}
+
+static
+int CCSymmFinish(
+                 SymCipherContext cipherCtx)
+{
+       if(cipherCtx) {
+        sslFree(cipherCtx);
+       }
+       return 0;
+}
+
+
+#else
+
+#define ENABLE_RC4      1
+#define ENABLE_3DES     1
+#define ENABLE_AES      1
+#define ENABLE_AES256   1
 
 /*
  * CommonCrypto-based symmetric cipher callouts
  */
-OSStatus CCSymmInit(
-       uint8_t *key,
-       uint8_t* iv,
-       CipherContext *cipherCtx,
-       SSLContext *ctx)
+#include <CommonCrypto/CommonCryptor.h>
+#include <CommonCrypto/CommonCryptorSPI.h>
+#include <assert.h>
+
+static
+CCAlgorithm CCAlg(SSL_CipherAlgorithm alg)
+{
+    switch(alg) {
+        case SSL_CipherAlgorithmAES_128_CBC:
+        case SSL_CipherAlgorithmAES_256_CBC:
+        case SSL_CipherAlgorithmAES_128_GCM:
+        case SSL_CipherAlgorithmAES_256_GCM:
+            return kCCAlgorithmAES128;          /* AES128 here means 128bit block size, not key size */
+        case SSL_CipherAlgorithm3DES_CBC:
+            return kCCAlgorithm3DES;
+        case SSL_CipherAlgorithmDES_CBC:
+            return kCCAlgorithmDES;
+        case SSL_CipherAlgorithmRC4_128:
+            return kCCAlgorithmRC4;
+        case SSL_CipherAlgorithmRC2_128:
+            return kCCAlgorithmRC2;
+        default:
+            assert(0);
+            return (CCAlgorithm)(-1); /* This will cause CCCryptorCreate to return an error */
+    }
+}
+
+static CCOptions CCOpt(CipherType cipherType)
 {
+#if 0
+    if(cipherType==aeadCipherType) return kCCModeGCM;
+#endif
+    return 0;
+}
+
+static
+int CCSymmInit(
+    const SSLSymmetricCipherParams *params,
+    int encrypting,
+       uint8_t *key, 
+       uint8_t* iv, 
+       SymCipherContext *cipherCtx)
+{
+    assert(cipherCtx!=NULL);
+
        /*
         * Cook up a CCCryptorRef. Assumes:
         *              cipherCtx->symCipher.keyAlg
@@ -51,62 +274,301 @@ OSStatus CCSymmInit(
         *              Resulting CCCryptorRef --> cipherCtx->cryptorRef
         */
        CCCryptorStatus ccrtn;
-       CCOperation op = cipherCtx->encrypting ? kCCEncrypt : kCCDecrypt;
+       CCOperation op = encrypting ? kCCEncrypt : kCCDecrypt;
+    CCCryptorRef cryptorRef = (CCCryptorRef)*cipherCtx;
 
-       if(cipherCtx->cryptorRef) {
-               CCCryptorRelease(cipherCtx->cryptorRef);
-               cipherCtx->cryptorRef = NULL;
+    /* FIXME: this should not be needed as long as CCSymFinish is called */
+       if(cryptorRef) {
+               CCCryptorRelease(cryptorRef);
+               cryptorRef = NULL;
        }
 
-       ccrtn = CCCryptorCreate(op, cipherCtx->symCipher->keyAlg,
-               0,              /* options - no padding, default CBC */
-               key, cipherCtx->symCipher->keySize,
+       ccrtn = CCCryptorCreate(op, CCAlg(params->keyAlg),
+        /* options - gcm or no padding, default CBC */
+        CCOpt(params->cipherType),
+               key, params->keySize,
                iv,
-               &cipherCtx->cryptorRef);
+               &cryptorRef);
        if(ccrtn) {
                sslErrorLog("CCCryptorCreate returned %d\n", (int)ccrtn);
-               return internalComponentErr;
+               return errSSLRecordInternal;
        }
-       return noErr;
+    *cipherCtx = (SymCipherContext)cryptorRef;
+       return 0;
 }
 
 /* same for en/decrypt */
-OSStatus CCSymmEncryptDecrypt(
-       const uint8_t *src,
-       uint8_t *dest,
-       size_t len,
-       CipherContext *cipherCtx,
-       SSLContext *ctx)
+static
+int CCSymmEncryptDecrypt(
+                              const uint8_t *src,
+                              uint8_t *dest,
+                              size_t len,
+                              SymCipherContext cipherCtx)
 {
        CCCryptorStatus ccrtn;
-
-       ASSERT(cipherCtx != NULL);
-       ASSERT(cipherCtx->cryptorRef != NULL);
-       if(cipherCtx->cryptorRef == NULL) {
+       CCCryptorRef cryptorRef = (CCCryptorRef)cipherCtx;
+       ASSERT(cryptorRef != NULL);
+       if(cryptorRef == NULL) {
                sslErrorLog("CCSymmEncryptDecrypt: NULL cryptorRef\n");
-               return internalComponentErr;
+               return errSSLRecordInternal;
        }
     size_t data_moved;
-       ccrtn = CCCryptorUpdate(cipherCtx->cryptorRef, src, len,
-               dest, len, &data_moved);
+       ccrtn = CCCryptorUpdate(cryptorRef, src, len,
+                            dest, len, &data_moved);
     assert(data_moved == len);
-       #if SSL_DEBUG
+#if SSL_DEBUG
        if(ccrtn) {
                sslErrorLog("CCSymmEncryptDecrypt: returned %d\n", (int)ccrtn);
-               return internalComponentErr;
+               return errSSLRecordInternal;
+       }
+#endif
+       return 0;
+}
+
+#if ENABLE_AES_GCM
+
+/* same for en/decrypt */
+static
+int CCSymmAEADSetIV(
+    const uint8_t *iv,
+    size_t len,
+    SymCipherContext cipherCtx)
+{
+       CCCryptorStatus ccrtn;
+       CCCryptorRef cryptorRef = (CCCryptorRef)cipherCtx;
+
+       ASSERT(cryptorRef != NULL);
+       if(cryptorRef == NULL) {
+               sslErrorLog("CCSymmAEADAddIV: NULL cryptorRef\n");
+               return errSecInternalComponent;
+       }
+       ccrtn = CCCryptorGCMAddIV(cryptorRef, iv, len);
+#if SSL_DEBUG
+       if(ccrtn) {
+               sslErrorLog("CCSymmAEADAddIV: returned %d\n", (int)ccrtn);
+               return errSSLRecordInternal;
+       }
+#endif
+       return 0;
+}
+
+/* same for en/decrypt */
+static
+int CCSymmAddADD(
+    const uint8_t *src,
+    size_t len,
+    SymCipherContext cipherCtx)
+{
+       CCCryptorStatus ccrtn;
+       CCCryptorRef cryptorRef = (CCCryptorRef)cipherCtx;
+
+       ASSERT(cryptorRef != NULL);
+       if(cryptorRef == NULL) {
+               sslErrorLog("CCSymmAddADD: NULL cryptorRef\n");
+               return errSSLRecordInternal;
+       }
+       ccrtn = CCCryptorGCMAddADD(cryptorRef, src, len);
+#if SSL_DEBUG
+       if(ccrtn) {
+               sslErrorLog("CCSymmAddADD: returned %d\n", (int)ccrtn);
+               return errSSLRecordInternal;
+       }
+#endif
+       return 0;
+}
+
+static
+int CCSymmAEADEncrypt(
+    const uint8_t *src,
+    uint8_t *dest,
+    size_t len,
+    SymCipherContext cipherCtx)
+{
+       CCCryptorStatus ccrtn;
+       CCCryptorRef cryptorRef = (CCCryptorRef)cipherCtx;
+
+       ASSERT(cryptorRef != NULL);
+       if(cryptorRef == NULL) {
+               sslErrorLog("CCSymmAEADEncrypt: NULL cryptorRef\n");
+               return errSSLRecordInternal;
+       }
+       ccrtn = CCCryptorGCMEncrypt(cryptorRef, src, len, dest);
+#if SSL_DEBUG
+       if(ccrtn) {
+               sslErrorLog("CCSymmAEADEncrypt: returned %d\n", (int)ccrtn);
+               return errSSLRecordInternal;
        }
-       #endif
-       return noErr;
+#endif
+       return 0;
 }
 
-OSStatus CCSymmFinish(
-       CipherContext *cipherCtx,
-       SSLContext *ctx)
+
+static
+int CCSymmAEADDecrypt(
+    const uint8_t *src,
+    uint8_t *dest,
+    size_t len,
+    SymCipherContext cipherCtx)
 {
-       if(cipherCtx->cryptorRef) {
-               CCCryptorRelease(cipherCtx->cryptorRef);
-               cipherCtx->cryptorRef = NULL;
+       CCCryptorStatus ccrtn;
+       CCCryptorRef cryptorRef = (CCCryptorRef)cipherCtx;
+
+       ASSERT(cipherCtx != NULL);
+       ASSERT(cipherCtx->cryptorRef != NULL);
+       if(cipherCtx->cryptorRef == NULL) {
+               sslErrorLog("CCSymmAEADDecrypt: NULL cryptorRef\n");
+               return errSSLRecordInternal;
+       }
+       ccrtn = CCCryptorGCMDecrypt(cryptorRef, src, len, dest);
+#if SSL_DEBUG
+       if(ccrtn) {
+               sslErrorLog("CCSymmAEADDecrypt: returned %d\n", (int)ccrtn);
+               return errSSLRecordInternal;
        }
-       return noErr;
+#endif
+       return 0;
 }
 
+
+static
+int CCSymmAEADDone(
+    uint8_t *mac,
+    size_t *macLen,
+    SymCipherContext cipherCtx)
+{
+       CCCryptorStatus ccrtn;
+       CCCryptorRef cryptorRef = (CCCryptorRef)cipherCtx;
+
+       ASSERT(cipherCtx != NULL);
+       ASSERT(cipherCtx->cryptorRef != NULL);
+       if(cipherCtx->cryptorRef == NULL) {
+               sslErrorLog("CCSymmAEADDone: NULL cryptorRef\n");
+               return errSSLRecordInternal;
+       }
+       ccrtn = CCCryptorGCMFinal(cipherCtx->cryptorRef, mac, macLen);
+    CCCryptorStatus ccrtn2 = CCCryptorGCMReset(cipherCtx->cryptorRef);
+    if (ccrtn == kCCSuccess)
+        ccrtn = ccrtn2;
+#if SSL_DEBUG
+       if(ccrtn) {
+               sslErrorLog("CCSymmAEADDone: returned %d\n", (int)ccrtn);
+               return errSSLRecordInternal;
+       }
+#endif
+       return 0;
+}
+#endif
+
+static
+int CCSymmFinish(
+       SymCipherContext cipherCtx)
+{
+       CCCryptorRef cryptorRef = (CCCryptorRef)cipherCtx;
+
+       if(cryptorRef) {
+               CCCryptorRelease(cryptorRef);
+       }
+       return 0;
+}
+
+#endif /* KERNEL */
+
+#if    ENABLE_DES
+const SSLSymmetricCipher SSLCipherDES_CBC = {
+    .params = &SSLCipherDES_CBCParams,
+    .c.cipher = {
+        .initialize = CCSymmInit,
+        .encrypt = CCSymmEncryptDecrypt,
+        .decrypt = CCSymmEncryptDecrypt
+    },
+    .finish = CCSymmFinish
+};
+#endif /* ENABLE_DES */
+
+#if    ENABLE_3DES
+const SSLSymmetricCipher SSLCipher3DES_CBC = {
+    .params = &SSLCipher3DES_CBCParams,
+    .c.cipher = {
+        .initialize = CCSymmInit,
+        .encrypt = CCSymmEncryptDecrypt,
+        .decrypt = CCSymmEncryptDecrypt
+    },
+    .finish = CCSymmFinish
+};
+#endif /* ENABLE_3DES */
+
+#if            ENABLE_RC4
+const SSLSymmetricCipher SSLCipherRC4_128 = {
+    .params = &SSLCipherRC4_128Params,
+    .c.cipher = {
+        .initialize = CCSymmInit,
+        .encrypt = CCSymmEncryptDecrypt,
+        .decrypt = CCSymmEncryptDecrypt
+    },
+    .finish = CCSymmFinish
+};
+#endif /* ENABLE_RC4 */
+
+#if            ENABLE_RC2
+const SSLSymmetricCipher SSLCipherRC2_128 = {
+    .params = &SSLCipherRC2_128Params,
+    .c.cipher = {
+        .initialize = CCSymmInit,
+        .encrypt = CCSymmEncryptDecrypt,
+        .decrypt = CCSymmEncryptDecrypt
+    },
+    .finish = CCSymmFinish
+};
+#endif /* ENABLE_RC2*/
+
+#if            ENABLE_AES
+const SSLSymmetricCipher SSLCipherAES_128_CBC = {
+    .params = &SSLCipherAES_128_CBCParams,
+    .c.cipher = {
+        .initialize = CCSymmInit,
+        .encrypt = CCSymmEncryptDecrypt,
+        .decrypt = CCSymmEncryptDecrypt
+    },
+    .finish = CCSymmFinish
+};
+#endif /* ENABLE_AES */
+
+#if ENABLE_AES256
+const SSLSymmetricCipher SSLCipherAES_256_CBC = {
+    .params = &SSLCipherAES_256_CBCParams,
+    .c.cipher = {
+        .initialize = CCSymmInit,
+        .encrypt = CCSymmEncryptDecrypt,
+        .decrypt = CCSymmEncryptDecrypt
+    },
+    .finish = CCSymmFinish
+};
+#endif /* ENABLE_AES256 */
+
+#if ENABLE_AES_GCM
+const SSLSymmetricCipher SSLCipherAES_128_GCM = {
+    .params = &SSLCipherAES_128_GCMParams,
+    .c.aead = {
+        .initialize = CCSymmInit,
+        .setIV = CCSymmAEADSetIV,
+        .update = CCSymmAddADD,
+        .encrypt = CCSymmAEADEncrypt,
+        .decrypt = CCSymmAEADDecrypt,
+        .done =  CCSymmAEADDone
+    },
+    .finish = CCSymmFinish
+};
+
+const SSLSymmetricCipher SSLCipherAES_256_GCM = {
+    .params = &SSLCipherAES_256_GCMParams,
+    .c.aead = {
+        .initialize = CCSymmInit,
+        .setIV = CCSymmAEADSetIV,
+        .update = CCSymmAddADD,
+        .encrypt = CCSymmAEADEncrypt,
+        .decrypt = CCSymmAEADDecrypt,
+        .done =  CCSymmAEADDone
+    },
+    .finish = CCSymmFinish
+};
+#endif /* ENABLE_AES_GCM */