Option to set current cert to server certificate.
[openssl.git] / crypto / cmac / cmac.c
index 5ec88b3ad7300a777815c3b5d0a825dc58f5a843..3e6afc70db085f86af24004efde95e32c6e11d8a 100644 (file)
@@ -51,6 +51,8 @@
  * ====================================================================
  */
 
+#define OPENSSL_FIPSAPI
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -75,19 +77,17 @@ struct CMAC_CTX_st
 
 /* Make temporary keys K1 and K2 */
 
-static void make_kn(unsigned char *k1, unsigned char *l, int bl)
+static void make_kn(unsigned char *k1, const unsigned char *l, int bl)
        {
        int i;
+       unsigned char c = l[0], carry = c>>7, cnext;
+
        /* Shift block to left, including carry */
-       for (i = 0; i < bl; i++)
-               {
-               k1[i] = l[i] << 1;
-               if (i < bl - 1 && l[i + 1] & 0x80)
-                       k1[i] |= 1;
-               }
+       for (i = 0; i < bl-1; i++, c = cnext)
+               k1[i] = (c << 1) | ((cnext=l[i+1]) >> 7);
+
        /* If MSB set fixup with R */
-       if (l[0] & 0x80)
-               k1[bl - 1] ^= bl == 16 ? 0x87 : 0x1b;
+       k1[i] = (c << 1) ^ ((0-carry)&(bl==16?0x87:0x1b));
        }
 
 CMAC_CTX *CMAC_CTX_new(void)
@@ -122,42 +122,63 @@ void CMAC_CTX_free(CMAC_CTX *ctx)
        OPENSSL_free(ctx);
        }
 
+int CMAC_CTX_copy(CMAC_CTX *out, const CMAC_CTX *in)
+       {
+       int bl;
+       if (in->nlast_block == -1)
+               return 0;
+       if (!EVP_CIPHER_CTX_copy(&out->cctx, &in->cctx))
+               return 0;
+       bl = M_EVP_CIPHER_CTX_block_size(&in->cctx);
+       memcpy(out->k1, in->k1, bl);
+       memcpy(out->k2, in->k2, bl);
+       memcpy(out->tbl, in->tbl, bl);
+       memcpy(out->last_block, in->last_block, bl);
+       out->nlast_block = in->nlast_block;
+       return 1;
+       }
+
 int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t keylen, 
                        const EVP_CIPHER *cipher, ENGINE *impl)
        {
-       static unsigned char zero_iv[EVP_MAX_BLOCK_LENGTH];
+       __fips_constseg
+       static const unsigned char zero_iv[EVP_MAX_BLOCK_LENGTH] = {0};
        /* All zeros means restart */
        if (!key && !cipher && !impl && keylen == 0)
                {
                /* Not initialised */
-               if (ctx->last_block == -1)
+               if (ctx->nlast_block == -1)
                        return 0;
-               if (!EVP_EncryptInit_ex(&ctx->cctx, NULL, NULL, NULL, zero_iv))
+               if (!M_EVP_EncryptInit_ex(&ctx->cctx, NULL, NULL, NULL, zero_iv))
                        return 0;
-               return 0;
+               memset(ctx->tbl, 0, M_EVP_CIPHER_CTX_block_size(&ctx->cctx));
+               ctx->nlast_block = 0;
+               return 1;
                }
        /* Initialiase context */
-       if (cipher && !EVP_EncryptInit_ex(&ctx->cctx, cipher, impl, NULL, NULL))
+       if (cipher && !M_EVP_EncryptInit_ex(&ctx->cctx, cipher, impl, NULL, NULL))
                return 0;
        /* Non-NULL key means initialisation complete */
        if (key)
                {
                int bl;
-               if (!EVP_CIPHER_CTX_cipher(&ctx->cctx))
+               if (!M_EVP_CIPHER_CTX_cipher(&ctx->cctx))
                        return 0;
                if (!EVP_CIPHER_CTX_set_key_length(&ctx->cctx, keylen))
                        return 0;
-               if (!EVP_EncryptInit_ex(&ctx->cctx, NULL, NULL, key, zero_iv))
+               if (!M_EVP_EncryptInit_ex(&ctx->cctx, NULL, NULL, key, zero_iv))
                        return 0;
-               bl = EVP_CIPHER_CTX_block_size(&ctx->cctx);
+               bl = M_EVP_CIPHER_CTX_block_size(&ctx->cctx);
                if (!EVP_Cipher(&ctx->cctx, ctx->tbl, zero_iv, bl))
                        return 0;
                make_kn(ctx->k1, ctx->tbl, bl);
                make_kn(ctx->k2, ctx->k1, bl);
                OPENSSL_cleanse(ctx->tbl, bl);
                /* Reset context again ready for first data block */
-               if (!EVP_EncryptInit_ex(&ctx->cctx, NULL, NULL, NULL, zero_iv))
+               if (!M_EVP_EncryptInit_ex(&ctx->cctx, NULL, NULL, NULL, zero_iv))
                        return 0;
+               /* Zero tbl so resume works */
+               memset(ctx->tbl, 0, bl);
                ctx->nlast_block = 0;
                }
        return 1;
@@ -171,7 +192,7 @@ int CMAC_Update(CMAC_CTX *ctx, const void *in, size_t dlen)
                return 0;
        if (dlen == 0)
                return 1;
-       bl = EVP_CIPHER_CTX_block_size(&ctx->cctx);
+       bl = M_EVP_CIPHER_CTX_block_size(&ctx->cctx);
        /* Copy into partial block if we need to */
        if (ctx->nlast_block > 0)
                {
@@ -205,18 +226,21 @@ int CMAC_Update(CMAC_CTX *ctx, const void *in, size_t dlen)
 
        }
 
-size_t CMAC_Final(CMAC_CTX *ctx, unsigned char *out)
+int CMAC_Final(CMAC_CTX *ctx, unsigned char *out, size_t *poutlen)
        {
        int i, bl, lb;
        if (ctx->nlast_block == -1)
                return 0;
-       bl = EVP_CIPHER_CTX_block_size(&ctx->cctx);
+       bl = M_EVP_CIPHER_CTX_block_size(&ctx->cctx);
+       *poutlen = (size_t)bl;
+       if (!out)
+               return 1;
        lb = ctx->nlast_block;
        /* Is last block complete? */
        if (lb == bl)
                {
                for (i = 0; i < bl; i++)
-                       ctx->last_block[i] ^= ctx->k1[i];
+                       out[i] = ctx->last_block[i] ^ ctx->k1[i];
                }
        else
                {
@@ -224,9 +248,25 @@ size_t CMAC_Final(CMAC_CTX *ctx, unsigned char *out)
                if (bl - lb > 1)
                        memset(ctx->last_block + lb + 1, 0, bl - lb - 1);
                for (i = 0; i < bl; i++)
-                       ctx->last_block[i] ^= ctx->k2[i];
+                       out[i] = ctx->last_block[i] ^ ctx->k2[i];
+               }
+       if (!EVP_Cipher(&ctx->cctx, out, out, bl))
+               {
+               OPENSSL_cleanse(out, bl);       
+               return 0;
                }
-       if (!EVP_Cipher(&ctx->cctx, out, ctx->last_block, bl))
+       return 1;
+       }
+
+int CMAC_resume(CMAC_CTX *ctx)
+       {
+       if (ctx->nlast_block == -1)
                return 0;
-       return bl;
+       /* The buffer "tbl" containes the last fully encrypted block
+        * which is the last IV (or all zeroes if no last encrypted block).
+        * The last block has not been modified since CMAC_final().
+        * So reinitliasing using the last decrypted block will allow
+        * CMAC to continue after calling CMAC_Final(). 
+        */
+       return M_EVP_EncryptInit_ex(&ctx->cctx, NULL, NULL, NULL, ctx->tbl);
        }