Add samba_crypto abstraction layer crypto
authorSimo Sorce <idra@samba.org>
Fri, 29 May 2015 21:29:03 +0000 (17:29 -0400)
committerSimo Sorce <idra@samba.org>
Sun, 7 Jun 2015 21:16:57 +0000 (17:16 -0400)
The samba_crypto API uses whatever available crypto libraries can be
found on the system. OpenSSL and GNUTLS are currently supported, more
can be supported.

The choice is done at build time. The interfaces are built to minimize
memory allocation (inclusing contexts), and be simple to use while
offering an interface based on samba own's data types.

Signed-off-by: Simo Sorce <simo@redhat.com>
lib/crypto/samba_crypto.c [new file with mode: 0644]
lib/crypto/samba_crypto.h [new file with mode: 0644]
lib/crypto/samba_crypto_test.c [new file with mode: 0644]
lib/crypto/wscript_build [changed mode: 0644->0755]
lib/crypto/wscript_configure [changed mode: 0644->0755]
source4/torture/local/local.c

diff --git a/lib/crypto/samba_crypto.c b/lib/crypto/samba_crypto.c
new file mode 100644 (file)
index 0000000..5ad8820
--- /dev/null
@@ -0,0 +1,304 @@
+/* The Samba Project Contributors - License in the COPYING file */
+
+#include "samba_crypto.h"
+
+#if CRYPTO_USE_OPENSSL
+#include <openssl/evp.h>
+
+struct samba_crypto_cipher_ctx {
+       EVP_CIPHER_CTX ctx;
+       enum samba_crypto_operation op;
+       bool cipher_is_aead;
+       bool cipher_is_ccm;
+};
+
+#elif CRYPTO_USE_GNUTLS
+struct samba_crypto_cipher_ctx {
+       gnutls_cipher_hd_t ctx;
+       enum samba_crypto_operation op;
+       bool cipher_is_aead;
+       bool cipher_is_ccm;
+};
+
+#else
+# error no crypto library available
+#endif
+
+int samba_crypto_cipher_ctx_size(void)
+{
+       return sizeof(struct samba_crypto_cipher_ctx);
+}
+
+#if CRYPTO_USE_OPENSSL
+
+/* older vesions of openssl used the same values but only had
+ * cipher-specific names. Newer versions define 'AEAD' generic
+ * names. Define them if not available. Thy have the same value
+ * as the cipher-secific ones. */
+#ifndef EVP_CTRL_AEAD_SET_IVLEN
+#define EVP_CTRL_AEAD_SET_IVLEN EVP_CTRL_GCM_SET_IVLEN
+#endif
+#ifndef EVP_CTRL_AEAD_SET_TAG
+#define EVP_CTRL_AEAD_SET_TAG EVP_CTRL_GCM_SET_TAG
+#endif
+#ifndef EVP_CTRL_AEAD_GET_TAG
+#define EVP_CTRL_AEAD_GET_TAG EVP_CTRL_GCM_GET_TAG
+#endif
+
+#define OS_EVP_OK 1
+#define OS_EVP_ERR 0
+#define OS_EVP_IS_ERR(val) ((val) == OS_EVP_ERR)
+
+struct samba_crypto_cipher {
+       const EVP_CIPHER *(*cipher)(void);
+} samba_crypto_ciphers[] = {
+       { NULL },
+       { EVP_aes_128_ccm },
+       { EVP_aes_128_gcm },
+};
+
+static bool samba_crypto_cipher_is_valid(enum samba_crypto_cipher_id id)
+{
+       if (id > SAMBA_CRYPTO_CIPHER_NONE &&
+           id < SAMBA_CRYPTO_CIPHER_END) {
+               return true;
+       }
+       return false;
+}
+
+static bool samba_crypto_cipher_is_aead(enum samba_crypto_cipher_id id)
+{
+       switch (id) {
+       case SAMBA_CRYPTO_CIPHER_AES_128_CCM:
+               return true;
+       case SAMBA_CRYPTO_CIPHER_AES_128_GCM:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool samba_crypto_cipher_is_ccm(enum samba_crypto_cipher_id id)
+{
+       return (id == SAMBA_CRYPTO_CIPHER_AES_128_CCM);
+}
+
+NTSTATUS samba_crypto_cipher_init(struct samba_crypto_cipher_ctx *ctx,
+                                 enum samba_crypto_cipher_id cipher,
+                                 DATA_BLOB *key_blob,
+                                 DATA_BLOB *iv_blob,
+                                 DATA_BLOB *authdata,
+                                 DATA_BLOB *authtag,
+                                 int ccm_inputbuffer_len,
+                                 enum samba_crypto_operation op)
+{
+       unsigned char *key = NULL;
+       unsigned char *iv = NULL;
+       NTSTATUS status;
+       int ret;
+       int enc;
+
+       if (!samba_crypto_cipher_is_valid(cipher)) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       ZERO_STRUCTP(ctx);
+
+       switch (op) {
+       case SAMBA_CRYPTO_ENCRYPT:
+               enc = 1;
+               break;
+       case SAMBA_CRYPTO_DECRYPT:
+               enc = 0;
+               break;
+       default:
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+       ctx->op = op;
+
+       if (samba_crypto_cipher_is_aead(cipher)) {
+               ctx->cipher_is_aead = true;
+       }
+
+       if (samba_crypto_cipher_is_ccm(cipher)) {
+               ctx->cipher_is_ccm = true;
+       }
+
+       EVP_CIPHER_CTX_init(&ctx->ctx);
+       ret = EVP_CipherInit_ex(&ctx->ctx,
+                               samba_crypto_ciphers[cipher].cipher(),
+                               NULL, NULL, NULL, enc);
+       if (OS_EVP_IS_ERR(ret)) {
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto done;
+       }
+
+       if (EVP_CIPHER_CTX_key_length(&ctx->ctx) != key_blob->length) {
+               status = NT_STATUS_INVALID_BUFFER_SIZE;
+               goto done;
+       }
+       key = (unsigned char *)key_blob->data;
+
+       if (iv_blob) {
+               iv = (unsigned char *)iv_blob->data;
+
+               if (ctx->cipher_is_aead) {
+                       ret = EVP_CIPHER_CTX_ctrl(&ctx->ctx,
+                                                 EVP_CTRL_AEAD_SET_IVLEN,
+                                                 iv_blob->length, NULL);
+                       if (OS_EVP_IS_ERR(ret)) {
+                               status = NT_STATUS_UNSUCCESSFUL;
+                               goto done;
+                       }
+               }
+       }
+
+       if (ctx->cipher_is_aead && authtag) {
+               if (ctx->op == SAMBA_CRYPTO_ENCRYPT &&
+                   ctx->cipher_is_ccm) {
+                       ret = EVP_CIPHER_CTX_ctrl(&ctx->ctx,
+                                                 EVP_CTRL_AEAD_SET_TAG,
+                                                 authtag->length, NULL);
+               } else if (ctx->op == SAMBA_CRYPTO_DECRYPT) {
+                       ret = EVP_CIPHER_CTX_ctrl(&ctx->ctx,
+                                                 EVP_CTRL_AEAD_SET_TAG,
+                                                 authtag->length,
+                                                 (void *)authtag->data);
+               }
+               if (OS_EVP_IS_ERR(ret)) {
+                       status = NT_STATUS_INVALID_PARAMETER;
+                       goto done;
+               }
+       }
+
+       ret = EVP_CipherInit_ex(&ctx->ctx, NULL, NULL, key, iv, enc);
+       if (OS_EVP_IS_ERR(ret)) {
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto done;
+       }
+
+       if (ctx->cipher_is_aead && authdata && authdata->length > 0) {
+               unsigned char *abuf = (unsigned char *)authdata->data;
+               int alen = authdata->length;
+               int tmplen;
+
+               if (ctx->cipher_is_ccm) {
+                       ret = EVP_CipherUpdate(&ctx->ctx, NULL,
+                                              &tmplen, NULL,
+                                              ccm_inputbuffer_len);
+                       if (OS_EVP_IS_ERR(ret)) {
+                               status = NT_STATUS_INTERNAL_ERROR;
+                               goto done;
+                       }
+               }
+
+               ret = EVP_CipherUpdate(&ctx->ctx,
+                                      NULL, &tmplen, abuf, alen);
+               if (OS_EVP_IS_ERR(ret)) {
+                       status = NT_STATUS_INTERNAL_ERROR;
+                       goto done;
+               }
+       }
+
+       status = NT_STATUS_OK;
+
+done:
+       if (!NT_STATUS_IS_OK(status)) {
+               samba_crypto_cipher_ctx_destroy(ctx);
+       }
+       return status;
+}
+
+int samba_crypto_cipher_block_size(struct samba_crypto_cipher_ctx *ctx)
+{
+       return EVP_CIPHER_block_size(EVP_CIPHER_CTX_cipher(&ctx->ctx));
+}
+
+NTSTATUS samba_crypto_cipher_crypt(struct samba_crypto_cipher_ctx *scc_ctx,
+                                  DATA_BLOB *plaintext,
+                                  DATA_BLOB *ciphertext,
+                                  DATA_BLOB *authtag,
+                                  bool finalize)
+{
+       EVP_CIPHER_CTX *ctx = &scc_ctx->ctx;
+       unsigned char *outbuf;
+       unsigned char *inbuf;
+       int outlen;
+       int inlen;
+       int totlen;
+       int ret;
+
+       switch (scc_ctx->op) {
+       case SAMBA_CRYPTO_ENCRYPT:
+               outbuf = (unsigned char *)ciphertext->data;
+               outlen = ciphertext->length;
+               inbuf = (unsigned char *)plaintext->data;
+               inlen = plaintext->length;
+               break;
+       case SAMBA_CRYPTO_DECRYPT:
+               outbuf = (unsigned char *)plaintext->data;
+               outlen = plaintext->length;
+               inbuf = (unsigned char *)ciphertext->data;
+               inlen = ciphertext->length;
+
+               break;
+       default:
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       ret = EVP_CipherUpdate(ctx, outbuf, &outlen, inbuf, inlen);
+       totlen = outlen;
+       if (finalize && !OS_EVP_IS_ERR(ret) &&
+           !(scc_ctx->cipher_is_ccm && scc_ctx->op == SAMBA_CRYPTO_DECRYPT)) {
+               outbuf += totlen;
+               outlen = ciphertext->length - totlen;
+               ret = EVP_CipherFinal_ex(ctx, outbuf, &outlen);
+               totlen += outlen;
+       }
+       if (scc_ctx->op == SAMBA_CRYPTO_ENCRYPT) {
+               if (OS_EVP_IS_ERR(ret)) {
+                       return NT_STATUS_ENCRYPTION_FAILED;
+               } else {
+                       ciphertext->length = totlen;
+               }
+               if (finalize && scc_ctx->cipher_is_aead) {
+                       int taglen = authtag->length;
+                       ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG,
+                                                 taglen,
+                                                 (void *)authtag->data);
+                       if (OS_EVP_IS_ERR(ret)) {
+                               return NT_STATUS_ENCRYPTION_FAILED;
+                       }
+               }
+       } else {
+               if (OS_EVP_IS_ERR(ret)) {
+                       return NT_STATUS_DECRYPTION_FAILED;
+               } else {
+                       plaintext->length = totlen;
+               }
+       }
+
+       return NT_STATUS_OK;
+}
+
+void samba_crypto_cipher_ctx_destroy(struct samba_crypto_cipher_ctx *ctx)
+{
+       (void)EVP_CIPHER_CTX_cleanup(&ctx->ctx);
+       ctx->op = SAMBA_CRYPTO_UNINITIALIZED;
+}
+#elif CRYPTO_USE_GNUTLS
+NTSTATUS samba_crypto_cipher_init(struct samba_cipher_ctx *ctx,
+                                 struct samba_crypto_cipher *cipher,
+                                 DATA_BLOB key,
+                                 DATA_BLOB iv,
+                                 enum samba_crypto_operation op);
+
+NTSTATUS samba_crypto_cipher_crypt(struct samba_cipher_ctx *ctx,
+                                  DATA_BLOB *plaintext,
+                                  DATA_BLOB *ciphertext,
+                                  DATA_BLOB *authtag);
+
+void samba_crypto_cipher_ctx_destroy(struct samba_crypto_cipher_ctx *ctx);
+#else
+# error no crypto library available
+#endif
diff --git a/lib/crypto/samba_crypto.h b/lib/crypto/samba_crypto.h
new file mode 100644 (file)
index 0000000..b9c464d
--- /dev/null
@@ -0,0 +1,49 @@
+/* The Samba Project Contributors - License in the COPYING file */
+
+#ifndef _SAMBA_CRYPTO_H_
+#define _SAMBA_CRYPTO_H_
+
+#include "includes.h"
+
+struct samba_crypto_cipher_ctx;
+
+int samba_crypto_cipher_ctx_size(void);
+
+#define SAMBA_CRYPTO_CIPHER_CTX(name) \
+       uint8_t stack_##name[samba_crypto_cipher_ctx_size()]; \
+       struct samba_crypto_cipher_ctx *name = \
+               (struct samba_crypto_cipher_ctx *)&stack_##name
+
+enum samba_crypto_cipher_id {
+       SAMBA_CRYPTO_CIPHER_NONE = 0,
+       SAMBA_CRYPTO_CIPHER_AES_128_CCM,
+       SAMBA_CRYPTO_CIPHER_AES_128_GCM,
+       SAMBA_CRYPTO_CIPHER_END
+};
+
+enum samba_crypto_operation {
+       SAMBA_CRYPTO_UNINITIALIZED,
+       SAMBA_CRYPTO_ENCRYPT,
+       SAMBA_CRYPTO_DECRYPT,
+};
+
+NTSTATUS samba_crypto_cipher_init(struct samba_crypto_cipher_ctx *ctx,
+                                 enum samba_crypto_cipher_id,
+                                 DATA_BLOB *key_blob,
+                                 DATA_BLOB *iv_blob,
+                                 DATA_BLOB *authdata,
+                                 DATA_BLOB *authtag,
+                                 int ccm_inputbuffer_len,
+                                 enum samba_crypto_operation op);
+
+int samba_crypto_cipher_block_size(struct samba_crypto_cipher_ctx *ctx);
+
+NTSTATUS samba_crypto_cipher_crypt(struct samba_crypto_cipher_ctx *ctx,
+                                  DATA_BLOB *plaintext,
+                                  DATA_BLOB *ciphertext,
+                                  DATA_BLOB *authtag,
+                                  bool finalize);
+
+void samba_crypto_cipher_ctx_destroy(struct samba_crypto_cipher_ctx *ctx);
+
+#endif /* _SAMBA_CRYPTO_H_ */
diff --git a/lib/crypto/samba_crypto_test.c b/lib/crypto/samba_crypto_test.c
new file mode 100644 (file)
index 0000000..2a0c1fd
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+   AES-GCM-128 tests
+
+   Copyright (C) Stefan Metzmacher 2014
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "replace.h"
+#include "../lib/util/samba_util.h"
+#include "samba_crypto.h"
+
+struct torture_context;
+bool torture_local_samba_crypto(struct torture_context *torture);
+
+enum tlsc_passfail {
+       TLSC_PASS = 0,
+       TLSC_FAIL,
+       TLSC_FAIL_ADATA
+};
+
+struct tlsc_testvector {
+       enum samba_crypto_cipher_id cipher;
+       DATA_BLOB K;
+       DATA_BLOB IV;
+       DATA_BLOB A;
+       DATA_BLOB P;
+       DATA_BLOB C;
+       DATA_BLOB T;
+};
+
+static void tlsc_print_errors(struct tlsc_testvector *tv,
+                             DATA_BLOB *P, DATA_BLOB *C, DATA_BLOB *T)
+{
+       printf("Cipher: %d\n", tv->cipher);
+       printf("K\n");
+       dump_data(0, tv->K.data, tv->K.length);
+       printf("IV\n");
+       dump_data(0, tv->IV.data, tv->IV.length);
+       printf("A\n");
+       dump_data(0, tv->A.data, tv->A.length);
+       printf("P\n");
+       dump_data(0, tv->P.data, tv->P.length);
+       if (P) {
+               printf("PV\n");
+               dump_data(0, P->data, P->length);
+       }
+       printf("C\n");
+       dump_data(0, tv->C.data, tv->C.length);
+       if (C) {
+               printf("CV\n");
+               dump_data(0, C->data, C->length);
+       }
+       printf("T\n");
+       dump_data(0, tv->T.data, tv->T.length);
+       if (T) {
+               printf("TV\n");
+               dump_data(0, T->data, T->length);
+       }
+}
+
+/*
+ This uses the test values from ...
+*/
+bool torture_local_samba_crypto(struct torture_context *torture)
+{
+       bool ret = true;
+       uint32_t i;
+       TALLOC_CTX *tctx = talloc_new(torture);
+       struct tlsc_testvector testarray[] = {
+               { .cipher = SAMBA_CRYPTO_CIPHER_AES_128_GCM,
+                 .K = strhex_to_data_blob(tctx,
+                       "00000000000000000000000000000000"),
+                 .IV = strhex_to_data_blob(tctx,
+                       "000000000000000000000000"),
+                 .A = data_blob_null,
+                 .P = strhex_to_data_blob(tctx,
+                       "00000000000000000000000000000000"),
+                 .C = strhex_to_data_blob(tctx,
+                       "0388dace60b6a392f328c2b971b2fe78"),
+                 .T = strhex_to_data_blob(tctx,
+                       "ab6e47d42cec13bdf53a67b21257bddf")
+               },
+               { .cipher = SAMBA_CRYPTO_CIPHER_AES_128_GCM,
+                 .K = strhex_to_data_blob(tctx,
+                       "feffe9928665731c6d6a8f9467308308"),
+                 .IV = strhex_to_data_blob(tctx,
+                       "cafebabefacedbaddecaf888"),
+                 .A = data_blob_null,
+                 .P = strhex_to_data_blob(tctx,
+                       "d9313225f88406e5a55909c5aff5269a"
+                       "86a7a9531534f7da2e4c303d8a318a72"
+                       "1c3c0c95956809532fcf0e2449a6b525"
+                       "b16aedf5aa0de657ba637b391aafd255"),
+                 .C = strhex_to_data_blob(tctx,
+                       "42831ec2217774244b7221b784d0d49c"
+                       "e3aa212f2c02a4e035c17e2329aca12e"
+                       "21d514b25466931c7d8f6a5aac84aa05"
+                       "1ba30b396a0aac973d58e091473f5985"),
+                 .T = strhex_to_data_blob(tctx,
+                       "4d5c2af327cd64a62cf35abd2ba6fab4")
+               },
+               { .cipher = SAMBA_CRYPTO_CIPHER_AES_128_GCM,
+                 .K = strhex_to_data_blob(tctx,
+                       "feffe9928665731c6d6a8f9467308308"),
+                 .IV = strhex_to_data_blob(tctx,
+                       "cafebabefacedbaddecaf888"),
+                 .A = strhex_to_data_blob(tctx,
+                       "feedfacedeadbeeffeedfacedeadbeef"
+                       "abaddad2"),
+                 .P = strhex_to_data_blob(tctx,
+                       "d9313225f88406e5a55909c5aff5269a"
+                       "86a7a9531534f7da2e4c303d8a318a72"
+                       "1c3c0c95956809532fcf0e2449a6b525"
+                       "b16aedf5aa0de657ba637b39"),
+                 .C = strhex_to_data_blob(tctx,
+                       "42831ec2217774244b7221b784d0d49c"
+                       "e3aa212f2c02a4e035c17e2329aca12e"
+                       "21d514b25466931c7d8f6a5aac84aa05"
+                       "1ba30b396a0aac973d58e091"),
+                 .T = strhex_to_data_blob(tctx,
+                       "5bc94fbc3221a5db94fae95ae7121a47"),
+               },
+               { .cipher = SAMBA_CRYPTO_CIPHER_AES_128_CCM,
+                 .K = strhex_to_data_blob(tctx,
+                       "197afb02ffbd8f699dacae87094d5243"),
+                 .IV = strhex_to_data_blob(tctx,
+                       "5a8aa485c316e9"),
+                 .A = data_blob_null,
+                 .P = strhex_to_data_blob(tctx,
+                       "3796cf51b8726652a4204733b8fbb047"
+                       "cf00fb91a9837e22"),
+                 .C = strhex_to_data_blob(tctx,
+                       "24ab9eeb0e5508cae80074f1070ee188"
+                       "a637171860881f1f"),
+                 .T = strhex_to_data_blob(tctx,
+                       "2d9a3fbc210595b7b8b1b41523111a8e")
+               },
+               { .cipher = SAMBA_CRYPTO_CIPHER_AES_128_CCM,
+                 .K = strhex_to_data_blob(tctx,
+                       "90929a4b0ac65b350ad1591611fe4829"),
+                 .IV = strhex_to_data_blob(tctx,
+                       "5a8aa485c316e9403aff859fbb"),
+                 .A = data_blob_null,
+                 .P = strhex_to_data_blob(tctx,
+                       "a16a2e741f1cd9717285b6d882c1fc53"
+                       "655e9773761ad697"),
+                 .C = strhex_to_data_blob(tctx,
+                       "4bfe4e35784f0a65b545477e5e2f4bae"
+                       "0e1e6fa717eaf2cb"),
+                 .T = strhex_to_data_blob(tctx,
+                       "6a9a970b9beb2ac1bd4fd62168f8378a")
+               },
+               { .cipher = SAMBA_CRYPTO_CIPHER_AES_128_CCM,
+                 .K = strhex_to_data_blob(tctx,
+                       "f9fdca4ac64fe7f014de0f43039c7571"),
+                 .IV = strhex_to_data_blob(tctx,
+                       "5a8aa485c316e9"),
+                 .A = strhex_to_data_blob(tctx,
+                       "3796cf51b8726652a4204733b8fbb047"
+                       "cf00fb91a9837e22ec22b1a268f88e2c"),
+                 .P = strhex_to_data_blob(tctx,
+                       "a265480ca88d5f536db0dc6abc40faf0"
+                       "d05be7a966977768"),
+                 .C = strhex_to_data_blob(tctx,
+                       "6be31860ca271ef448de8f8d8b39346d"
+                       "af4b81d7e92d65b3"),
+                 .T = strhex_to_data_blob(tctx,
+                       "38f125fa")
+               },
+               { .cipher = SAMBA_CRYPTO_CIPHER_AES_128_CCM,
+                 .K = strhex_to_data_blob(tctx,
+                       "26511fb51fcfa75cb4b44da75a6e5a0e"),
+                 .IV = strhex_to_data_blob(tctx,
+                       "5a8aa485c316e9403aff859fbb"),
+                 .A = strhex_to_data_blob(tctx,
+                       "a16a2e741f1cd9717285b6d882c1fc53"
+                       "655e9773761ad697a7ee6410184c7982"),
+                 .P = strhex_to_data_blob(tctx,
+                       "8739b4bea1a099fe547499cbc6d1b13d"
+                       "849b8084c9b6acc5"),
+                 .C = strhex_to_data_blob(tctx,
+                       "50038b5fdd364ee747b70d00bd36840e"
+                       "ce4ea19998123375"),
+                 .T = strhex_to_data_blob(tctx,
+                       "c0a458bfcafa3b2609afe0f825cbf503")
+               },
+               { 0 }
+       };
+
+       if (!tctx) { return false; };
+
+       for (i = 0; testarray[i].T.length != 0; i++) {
+               SAMBA_CRYPTO_CIPHER_CTX(ctx);
+               DATA_BLOB T = { 0 };
+               DATA_BLOB C = { 0 };
+               NTSTATUS status;
+               int err;
+
+               status = samba_crypto_cipher_init(ctx,
+                                                 testarray[i].cipher,
+                                                 &testarray[i].K,
+                                                 &testarray[i].IV,
+                                                 &testarray[i].A,
+                                                 &testarray[i].T,
+                                                 testarray[i].P.length,
+                                                 SAMBA_CRYPTO_ENCRYPT);
+               if (!NT_STATUS_IS_OK(status)) {
+                       printf("%s: aes_gcm_128 test[%u]: failed [%x]\n",
+                              __location__, i, NT_STATUS_V(status));
+                       tlsc_print_errors(&testarray[i], NULL, NULL, NULL);
+                       ret = false;
+                       goto fail;
+               }
+
+               C = data_blob_talloc_zero(tctx, testarray[i].P.length);
+               T = data_blob_talloc_zero(tctx, testarray[i].T.length);
+
+               status = samba_crypto_cipher_crypt(ctx, &testarray[i].P,
+                                                  &C, &T, true);
+               if (!NT_STATUS_IS_OK(status)) {
+                       printf("%s: aes_gcm_128 test[%u]: failed\n",
+                              __location__, i);
+                       tlsc_print_errors(&testarray[i], NULL, NULL, NULL);
+                       ret = false;
+                       goto fail;
+               }
+
+               err = memcmp(testarray[i].T.data, T.data, T.length);
+               if (err != 0) {
+                       printf("%s: aes_gcm_128 test[%u]: failed\n",
+                              __location__, i);
+                       tlsc_print_errors(&testarray[i], NULL, &C, &T);
+                       ret = false;
+                       goto fail;
+               }
+
+               err = memcmp(testarray[i].C.data, C.data, C.length);
+               if (err != 0) {
+                       printf("%s: aes_gcm_128 test[%u]: failed\n",
+                               __location__, i);
+                       tlsc_print_errors(&testarray[i], NULL, &C, &T);
+                       ret = false;
+                       goto fail;
+               }
+       }
+
+       for (i = 0; testarray[i].T.length != 0; i++) {
+               SAMBA_CRYPTO_CIPHER_CTX(ctx);
+               DATA_BLOB P = { 0 };
+               NTSTATUS status;
+               int err;
+
+               status = samba_crypto_cipher_init(ctx,
+                                                 testarray[i].cipher,
+                                                 &testarray[i].K,
+                                                 &testarray[i].IV,
+                                                 &testarray[i].A,
+                                                 &testarray[i].T,
+                                                 testarray[i].C.length,
+                                                 SAMBA_CRYPTO_DECRYPT);
+               if (!NT_STATUS_IS_OK(status)) {
+                       printf("%s: aes_gcm_128 test[%u]: failed\n",
+                               __location__, i);
+                       tlsc_print_errors(&testarray[i], NULL, NULL, NULL);
+                       ret = false;
+                       goto fail;
+               }
+
+               P = data_blob_talloc_zero(tctx, testarray[i].C.length);
+
+               status = samba_crypto_cipher_crypt(ctx,
+                                                  &P, &testarray[i].C,
+                                                  NULL, true);
+               if (!NT_STATUS_IS_OK(status)) {
+                       printf("%s: aes_gcm_128 test[%u]: failed\n",
+                               __location__, i);
+                       tlsc_print_errors(&testarray[i], NULL, NULL, NULL);
+                       ret = false;
+                       goto fail;
+               }
+
+               err = memcmp(testarray[i].P.data, P.data, P.length);
+               if (err != 0) {
+                       printf("%s: aes_gcm_128 test[%u]: failed\n",
+                              __location__, i);
+                       tlsc_print_errors(&testarray[i], &P, NULL, NULL);
+                       ret = false;
+                       goto fail;
+               }
+       }
+
+       for (i = 0; testarray[i].T.length != 0; i++) {
+               SAMBA_CRYPTO_CIPHER_CTX(ctx);
+               DATA_BLOB T = { 0 };
+               DATA_BLOB C = { 0 };
+               DATA_BLOB P;
+               DATA_BLOB CJ;
+               NTSTATUS status;
+               size_t j;
+               int err;
+
+               if (testarray[i].cipher == SAMBA_CRYPTO_CIPHER_AES_128_CCM) {
+                       /* samba_crypto's CCM can't do chunked updates */
+                       continue;
+               }
+
+               status = samba_crypto_cipher_init(ctx,
+                                                 testarray[i].cipher,
+                                                 &testarray[i].K,
+                                                 &testarray[i].IV,
+                                                 &testarray[i].A,
+                                                 &testarray[i].T,
+                                                 testarray[i].P.length,
+                                                 SAMBA_CRYPTO_ENCRYPT);
+               if (!NT_STATUS_IS_OK(status)) {
+                       printf("%s: aes_gcm_128 test[%u]: failed\n",
+                              __location__, i);
+                       tlsc_print_errors(&testarray[i], NULL, NULL, NULL);
+                       ret = false;
+                       goto fail;
+               }
+
+               C = data_blob_talloc_zero(tctx, testarray[i].P.length);
+               T = data_blob_talloc_zero(tctx, testarray[i].T.length);
+
+               CJ = C;
+               P.length = 1;
+               for (j = 0; j < testarray[i].P.length; j++) {
+                       bool finalize = (j == (testarray[i].P.length - 1));
+                       P.data = &testarray[i].P.data[j];
+                       status = samba_crypto_cipher_crypt(ctx, &P, &CJ, &T,
+                                                          finalize);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               printf("%s: aes_gcm_128 test[%u]: failed\n",
+                                       __location__, i);
+                               tlsc_print_errors(&testarray[i], NULL, &C, &T);
+                               ret = false;
+                               goto fail;
+                       }
+                       CJ.data += CJ.length;
+                       CJ.length = C.length - (CJ.data - C.data);
+               }
+               C.length = CJ.data - C.data;
+
+               err = memcmp(testarray[i].T.data, T.data, T.length);
+               if (err != 0) {
+                       printf("%s: aes_gcm_128 test[%u]: failed\n",
+                              __location__, i);
+                       tlsc_print_errors(&testarray[i], NULL, &C, &T);
+                       ret = false;
+                       goto fail;
+               }
+
+               err = memcmp(testarray[i].C.data, C.data, C.length);
+               if (err != 0) {
+                       printf("%s: aes_gcm_128 test[%u]: failed\n",
+                              __location__, i);
+                       tlsc_print_errors(&testarray[i], NULL, &C, &T);
+                       ret = false;
+                       goto fail;
+               }
+       }
+
+       for (i = 0; testarray[i].T.length != 0; i++) {
+               SAMBA_CRYPTO_CIPHER_CTX(ctx);
+               DATA_BLOB P = { 0 };
+               DATA_BLOB C;
+               DATA_BLOB PJ;
+               NTSTATUS status;
+               size_t j;
+               int err;
+
+               if (testarray[i].cipher == SAMBA_CRYPTO_CIPHER_AES_128_CCM) {
+                       /* samba_crypto's CCM can't do chunked updates */
+                       continue;
+               }
+
+               status = samba_crypto_cipher_init(ctx,
+                                                 testarray[i].cipher,
+                                                 &testarray[i].K,
+                                                 &testarray[i].IV,
+                                                 &testarray[i].A,
+                                                 &testarray[i].T,
+                                                 testarray[i].C.length,
+                                                 SAMBA_CRYPTO_DECRYPT);
+               if (!NT_STATUS_IS_OK(status)) {
+                       printf("%s: aes_gcm_128 test[%u]: failed\n",
+                               __location__, i);
+                       tlsc_print_errors(&testarray[i], NULL, NULL, NULL);
+                       ret = false;
+                       goto fail;
+               }
+
+               P = data_blob_talloc_zero(tctx, testarray[i].C.length);
+
+               PJ = P;
+               C.length = 1;
+               for (j = 0; j < testarray[i].C.length; j++) {
+                       bool finalize = (j == (testarray[i].C.length - 1));
+                       C.data = &testarray[i].C.data[j];
+                       status = samba_crypto_cipher_crypt(ctx, &PJ, &C, NULL,
+                                                          finalize);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               printf("%s: aes_gcm_128 test[%u]: failed\n",
+                                       __location__, i);
+                               tlsc_print_errors(&testarray[i], &P,
+                                                 NULL, NULL);
+                               ret = false;
+                               goto fail;
+                       }
+                       PJ.data += PJ.length;
+                       PJ.length = P.length - (PJ.data - P.data);
+               }
+               P.length = PJ.data - P.data;
+
+               err = memcmp(testarray[i].P.data, P.data, P.length);
+               if (err != 0) {
+                       printf("%s: aes_gcm_128 test[%u]: failed\n",
+                              __location__, i);
+                       tlsc_print_errors(&testarray[i], &P, NULL, NULL);
+                       ret = false;
+                       goto fail;
+               }
+       }
+
+ fail:
+       talloc_free(tctx);
+       return ret;
+}
old mode 100644 (file)
new mode 100755 (executable)
index f2326a2..570ae50
@@ -18,9 +18,21 @@ bld.SAMBA_SUBSYSTEM('LIBCRYPTO',
         deps='talloc' + extra_deps
         )
 
+sc_deps = ''
+if bld.CONFIG_SET('CRYPTO_USE_OPENSSL'):
+       sc_deps = 'crypto'
+elif bld.CONFIG_SET('CRYPTO_USE_GNUTLS'):
+       sc_deps = 'gnutls'
+
+bld.SAMBA_SUBSYSTEM('LIBSAMBACRYPTO',
+       source='samba_crypto.c',
+       deps=sc_deps)
+
 bld.SAMBA_SUBSYSTEM('TORTURE_LIBCRYPTO',
-       source='md4test.c md5test.c hmacmd5test.c aes_cmac_128_test.c aes_gcm_128_test.c',
+       source='''md4test.c md5test.c hmacmd5test.c
+       aes_cmac_128_test.c aes_gcm_128_test.c
+       samba_crypto_test.c''',
        autoproto='test_proto.h',
-       deps='LIBCRYPTO'
+       deps='LIBCRYPTO LIBSAMBACRYPTO'
        )
 
old mode 100644 (file)
new mode 100755 (executable)
index 130acec..31d5dde
@@ -1,3 +1,5 @@
+#!/usr/bin/env python
+
 if not conf.CHECK_FUNCS_IN('MD5Init', 'bsd', headers='bsd/md5.h',
     checklibc=True):
     conf.CHECK_FUNCS_IN('MD5Init', 'md5', headers='sys/md5.h',
@@ -13,3 +15,8 @@ if conf.CHECK_FUNCS('SHA256_Update'):
        conf.DEFINE('SHA256_RENAME_NEEDED', 1)
 if conf.CHECK_FUNCS('SHA512_Update'):
        conf.DEFINE('SHA512_RENAME_NEEDED', 1)
+
+if conf.CHECK_FUNCS_IN('EVP_CipherInit_ex', 'crypto', headers='openssl/evp.h'):
+    conf.DEFINE('CRYPTO_USE_OPENSSL', 1)
+else:
+    conf.DEFINE('CRYPTO_USE_GNUTLS', 1)
index 5d3b4e1aa243be4f61e2deebd5cb286330c76f8c..d0c035bd16b49e32393d2d9c5de1e571ad04f227 100644 (file)
@@ -94,6 +94,9 @@ NTSTATUS torture_local_init(void)
        torture_suite_add_simple_test(suite, "crypto.aes_gcm_128",
                                      torture_local_crypto_aes_gcm_128);
 
+       torture_suite_add_simple_test(suite, "samba.crypto",
+                                     torture_local_samba_crypto);
+
        for (i = 0; suite_generators[i]; i++)
                torture_suite_add_suite(suite,
                                        suite_generators[i](talloc_autofree_context()));