*/
/*
- * 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
* 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 */