ipsec: add support for RFC-4543 ENCR_NULL_AUTH_AES_GMAC
[vpp.git] / src / plugins / crypto_openssl / main.c
index 38da276..e5b142e 100644 (file)
@@ -15,6 +15,8 @@
  *------------------------------------------------------------------
  */
 
+#include <sys/syscall.h>
+
 #include <openssl/evp.h>
 #include <openssl/hmac.h>
 #include <openssl/rand.h>
@@ -49,7 +51,10 @@ static openssl_per_thread_data_t *per_thread_data = 0;
   _ (gcm, AES_256_GCM, EVP_aes_256_gcm, 8)                                    \
   _ (cbc, AES_128_CTR, EVP_aes_128_ctr, 8)                                    \
   _ (cbc, AES_192_CTR, EVP_aes_192_ctr, 8)                                    \
-  _ (cbc, AES_256_CTR, EVP_aes_256_ctr, 8)
+  _ (cbc, AES_256_CTR, EVP_aes_256_ctr, 8)                                    \
+  _ (null_gmac, AES_128_NULL_GMAC, EVP_aes_128_gcm, 8)                        \
+  _ (null_gmac, AES_192_NULL_GMAC, EVP_aes_192_gcm, 8)                        \
+  _ (null_gmac, AES_256_NULL_GMAC, EVP_aes_256_gcm, 8)
 
 #define foreach_openssl_chacha20_evp_op                                       \
   _ (chacha20_poly1305, CHACHA20_POLY1305, EVP_chacha20_poly1305, 8)
@@ -102,14 +107,8 @@ openssl_ops_enc_cbc (vlib_main_t *vm, vnet_crypto_op_t *ops[],
       vnet_crypto_key_t *key = vnet_crypto_get_key (op->key_index);
       int out_len = 0;
 
-      if (op->flags & VNET_CRYPTO_OP_FLAG_INIT_IV)
-       RAND_bytes (op->iv, iv_len);
-
       EVP_EncryptInit_ex (ctx, cipher, NULL, key->data, op->iv);
 
-      if (op->flags & VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS)
-       EVP_CIPHER_CTX_set_padding (ctx, 0);
-
       if (op->flags & VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS)
        {
          chp = chunks + op->chunk_index;
@@ -165,9 +164,6 @@ openssl_ops_dec_cbc (vlib_main_t *vm, vnet_crypto_op_t *ops[],
 
       EVP_DecryptInit_ex (ctx, cipher, NULL, key->data, op->iv);
 
-      if (op->flags & VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS)
-       EVP_CIPHER_CTX_set_padding (ctx, 0);
-
       if (op->flags & VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS)
        {
          chp = chunks + op->chunk_index;
@@ -206,7 +202,8 @@ openssl_ops_dec_cbc (vlib_main_t *vm, vnet_crypto_op_t *ops[],
 static_always_inline u32
 openssl_ops_enc_aead (vlib_main_t *vm, vnet_crypto_op_t *ops[],
                      vnet_crypto_op_chunk_t *chunks, u32 n_ops,
-                     const EVP_CIPHER *cipher, int is_gcm, const int iv_len)
+                     const EVP_CIPHER *cipher, int is_gcm, int is_gmac,
+                     const int iv_len)
 {
   openssl_per_thread_data_t *ptd = vec_elt_at_index (per_thread_data,
                                                     vm->thread_index);
@@ -219,9 +216,6 @@ openssl_ops_enc_aead (vlib_main_t *vm, vnet_crypto_op_t *ops[],
       vnet_crypto_key_t *key = vnet_crypto_get_key (op->key_index);
       int len = 0;
 
-      if (op->flags & VNET_CRYPTO_OP_FLAG_INIT_IV)
-       RAND_bytes (op->iv, 8);
-
       EVP_EncryptInit_ex (ctx, cipher, 0, 0, 0);
       if (is_gcm)
        EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL);
@@ -233,26 +227,36 @@ openssl_ops_enc_aead (vlib_main_t *vm, vnet_crypto_op_t *ops[],
          chp = chunks + op->chunk_index;
          for (j = 0; j < op->n_chunks; j++)
            {
-             EVP_EncryptUpdate (ctx, chp->dst, &len, chp->src, chp->len);
+             EVP_EncryptUpdate (ctx, is_gmac ? 0 : chp->dst, &len, chp->src,
+                                chp->len);
              chp += 1;
            }
        }
       else
-       EVP_EncryptUpdate (ctx, op->dst, &len, op->src, op->len);
-      EVP_EncryptFinal_ex (ctx, op->dst + len, &len);
+       EVP_EncryptUpdate (ctx, is_gmac ? 0 : op->dst, &len, op->src, op->len);
+      EVP_EncryptFinal_ex (ctx, is_gmac ? 0 : op->dst + len, &len);
       EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_AEAD_GET_TAG, op->tag_len, op->tag);
       op->status = VNET_CRYPTO_OP_STATUS_COMPLETED;
     }
   return n_ops;
 }
 
+static_always_inline u32
+openssl_ops_enc_null_gmac (vlib_main_t *vm, vnet_crypto_op_t *ops[],
+                          vnet_crypto_op_chunk_t *chunks, u32 n_ops,
+                          const EVP_CIPHER *cipher, const int iv_len)
+{
+  return openssl_ops_enc_aead (vm, ops, chunks, n_ops, cipher,
+                              /* is_gcm */ 1, /* is_gmac */ 1, iv_len);
+}
+
 static_always_inline u32
 openssl_ops_enc_gcm (vlib_main_t *vm, vnet_crypto_op_t *ops[],
                     vnet_crypto_op_chunk_t *chunks, u32 n_ops,
                     const EVP_CIPHER *cipher, const int iv_len)
 {
   return openssl_ops_enc_aead (vm, ops, chunks, n_ops, cipher,
-                              /* is_gcm */ 1, iv_len);
+                              /* is_gcm */ 1, /* is_gmac */ 0, iv_len);
 }
 
 static_always_inline __clib_unused u32
@@ -261,13 +265,14 @@ openssl_ops_enc_chacha20_poly1305 (vlib_main_t *vm, vnet_crypto_op_t *ops[],
                                   const EVP_CIPHER *cipher, const int iv_len)
 {
   return openssl_ops_enc_aead (vm, ops, chunks, n_ops, cipher,
-                              /* is_gcm */ 0, iv_len);
+                              /* is_gcm */ 0, /* is_gmac */ 0, iv_len);
 }
 
 static_always_inline u32
 openssl_ops_dec_aead (vlib_main_t *vm, vnet_crypto_op_t *ops[],
                      vnet_crypto_op_chunk_t *chunks, u32 n_ops,
-                     const EVP_CIPHER *cipher, int is_gcm, const int iv_len)
+                     const EVP_CIPHER *cipher, int is_gcm, int is_gmac,
+                     const int iv_len)
 {
   openssl_per_thread_data_t *ptd = vec_elt_at_index (per_thread_data,
                                                     vm->thread_index);
@@ -291,15 +296,19 @@ openssl_ops_dec_aead (vlib_main_t *vm, vnet_crypto_op_t *ops[],
          chp = chunks + op->chunk_index;
          for (j = 0; j < op->n_chunks; j++)
            {
-             EVP_DecryptUpdate (ctx, chp->dst, &len, chp->src, chp->len);
+             EVP_DecryptUpdate (ctx, is_gmac ? 0 : chp->dst, &len, chp->src,
+                                chp->len);
              chp += 1;
            }
        }
       else
-       EVP_DecryptUpdate (ctx, op->dst, &len, op->src, op->len);
+       {
+         EVP_DecryptUpdate (ctx, is_gmac ? 0 : op->dst, &len, op->src,
+                            op->len);
+       }
       EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_AEAD_SET_TAG, op->tag_len, op->tag);
 
-      if (EVP_DecryptFinal_ex (ctx, op->dst + len, &len) > 0)
+      if (EVP_DecryptFinal_ex (ctx, is_gmac ? 0 : op->dst + len, &len) > 0)
        op->status = VNET_CRYPTO_OP_STATUS_COMPLETED;
       else
        {
@@ -310,13 +319,22 @@ openssl_ops_dec_aead (vlib_main_t *vm, vnet_crypto_op_t *ops[],
   return n_ops - n_fail;
 }
 
+static_always_inline u32
+openssl_ops_dec_null_gmac (vlib_main_t *vm, vnet_crypto_op_t *ops[],
+                          vnet_crypto_op_chunk_t *chunks, u32 n_ops,
+                          const EVP_CIPHER *cipher, const int iv_len)
+{
+  return openssl_ops_dec_aead (vm, ops, chunks, n_ops, cipher,
+                              /* is_gcm */ 1, /* is_gmac */ 1, iv_len);
+}
+
 static_always_inline u32
 openssl_ops_dec_gcm (vlib_main_t *vm, vnet_crypto_op_t *ops[],
                     vnet_crypto_op_chunk_t *chunks, u32 n_ops,
                     const EVP_CIPHER *cipher, const int iv_len)
 {
   return openssl_ops_dec_aead (vm, ops, chunks, n_ops, cipher,
-                              /* is_gcm */ 1, iv_len);
+                              /* is_gcm */ 1, /* is_gmac */ 0, iv_len);
 }
 
 static_always_inline __clib_unused u32
@@ -325,7 +343,7 @@ openssl_ops_dec_chacha20_poly1305 (vlib_main_t *vm, vnet_crypto_op_t *ops[],
                                   const EVP_CIPHER *cipher, const int iv_len)
 {
   return openssl_ops_dec_aead (vm, ops, chunks, n_ops, cipher,
-                              /* is_gcm */ 0, iv_len);
+                              /* is_gcm */ 0, /* is_gmac */ 0, iv_len);
 }
 
 static_always_inline u32
@@ -474,9 +492,12 @@ crypto_openssl_init (vlib_main_t * vm)
 {
   vlib_thread_main_t *tm = vlib_get_thread_main ();
   openssl_per_thread_data_t *ptd;
-  u8 *seed_data = 0;
-  time_t t;
-  pid_t pid;
+  u8 seed[32];
+
+  if (syscall (SYS_getrandom, &seed, sizeof (seed), 0) != sizeof (seed))
+    return clib_error_return_unix (0, "getrandom() failed");
+
+  RAND_seed (seed, sizeof (seed));
 
   u32 eidx = vnet_crypto_register_engine (vm, "openssl", 50, "OpenSSL");
 
@@ -513,6 +534,7 @@ crypto_openssl_init (vlib_main_t * vm)
   vec_foreach (ptd, per_thread_data)
   {
     ptd->evp_cipher_ctx = EVP_CIPHER_CTX_new ();
+    EVP_CIPHER_CTX_set_padding (ptd->evp_cipher_ctx, 0);
 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
     ptd->hmac_ctx = HMAC_CTX_new ();
     ptd->hash_ctx = EVP_MD_CTX_create ();
@@ -522,16 +544,6 @@ crypto_openssl_init (vlib_main_t * vm)
 #endif
   }
 
-  t = time (NULL);
-  pid = getpid ();
-  vec_add (seed_data, &t, sizeof (t));
-  vec_add (seed_data, &pid, sizeof (pid));
-  vec_add (seed_data, &seed_data, sizeof (seed_data));
-
-  RAND_seed ((const void *) seed_data, vec_len (seed_data));
-
-  vec_free (seed_data);
-
   return 0;
 }