]> The Tcpdump Group git mirrors - tcpdump/commitdiff
Put the crypto stuff into a common routine.
authorGuy Harris <[email protected]>
Mon, 6 Jan 2020 03:25:00 +0000 (19:25 -0800)
committerGuy Harris <[email protected]>
Mon, 6 Jan 2020 03:25:00 +0000 (19:25 -0800)
That makes it easier to 1) change it and 2) use different crypto
libraries for it.

print-esp.c

index ae8cb038937b145ed8325394398b9a5ec916afaa..844522ec269bb38ddb62a30bc962426d601b31c1 100644 (file)
@@ -178,6 +178,92 @@ set_cipher_parameters(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
 }
 #endif
 
+static u_char *
+do_decrypt(netdissect_options *ndo, const char *caller, struct sa_list *sa,
+    const u_char *iv, const u_char *ct, unsigned int ctlen)
+{
+       EVP_CIPHER_CTX *ctx;
+       unsigned int block_size;
+       unsigned int ptlen;
+       u_char *pt;
+       int len;
+
+       ctx = EVP_CIPHER_CTX_new();
+       if (ctx == NULL) {
+               /*
+                * Failed to initialize the cipher context.
+                * From a look at the OpenSSL code, this appears to
+                * mean "couldn't allocate memory for the cipher context";
+                * note that we're not passing any parameters, so there's
+                * not much else it can mean.
+                */
+               (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
+                   "%s: can't allocate memory for cipher context", caller);
+               return NULL;
+       }
+
+       if (set_cipher_parameters(ctx, sa->evp, sa->secret, NULL) < 0) {
+               EVP_CIPHER_CTX_free(ctx);
+               (*ndo->ndo_warning)(ndo, "%s: espkey init failed", caller);
+               return NULL;
+       }
+       if (set_cipher_parameters(ctx, NULL, NULL, iv) < 0) {
+               EVP_CIPHER_CTX_free(ctx);
+               (*ndo->ndo_warning)(ndo, "%s: IV init failed", caller);
+               return NULL;
+       }
+
+       /*
+        * At least as I read RFC 5996 section 3.14 and RFC 4303 section 2.4,
+        * if the cipher has a block size of which the ciphertext's size must
+        * be a multiple, the payload must be padded to make that happen, so
+        * the ciphertext length must be a multiple of the block size.  Fail
+        * if that's not the case.
+        */
+       block_size = (unsigned int)EVP_CIPHER_CTX_block_size(ctx);
+       if ((ctlen % block_size) != 0) {
+               EVP_CIPHER_CTX_free(ctx);
+               (*ndo->ndo_warning)(ndo,
+                   "%s: ciphertext size %u is not a multiple of the cipher block size %u",
+                   caller, ctlen, block_size);
+               return NULL;
+       }
+
+       /*
+        * Attempt to allocate a buffer for the decrypted data, because
+        * we can't decrypt on top of the input buffer.
+        */
+       ptlen = ctlen;
+       pt = (u_char *)malloc(ptlen);
+       if (pt == NULL) {
+               EVP_CIPHER_CTX_free(ctx);
+               (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
+                   "%s: can't allocate memory for decryption buffer", caller);
+               return NULL;
+       }
+
+       /*
+        * The size of the ciphertext handed to us is a multiple of the
+        * cipher block size, so we don't need to worry about padding.
+        */
+       if (!EVP_CIPHER_CTX_set_padding(ctx, 0)) {
+               free(pt);
+               EVP_CIPHER_CTX_free(ctx);
+               (*ndo->ndo_warning)(ndo,
+                   "%s: EVP_CIPHER_CTX_set_padding failed", caller);
+               return NULL;
+       }
+       if (!EVP_DecryptUpdate(ctx, pt, &len, ct, ctlen)) {
+               free(pt);
+               EVP_CIPHER_CTX_free(ctx);
+               (*ndo->ndo_warning)(ndo, "%s: EVP_DecryptUpdate failed",
+                   caller);
+               return NULL;
+       }
+       EVP_CIPHER_CTX_free(ctx);
+       return pt;
+}
+
 /*
  * This will allocate a new buffer containing the decrypted data.
  * It returns 1 on success and 0 on failure.
@@ -201,11 +287,7 @@ int esp_print_decrypt_buffer_by_ikev2(netdissect_options *ndo,
        const u_char *iv;
        const u_char *ct;
        unsigned int ctlen;
-       int len;
-       EVP_CIPHER_CTX *ctx;
-       unsigned int block_size;
        u_char *pt;
-       u_int ptlen;
 
        /* initiator arg is any non-zero value */
        if(initiator) initiator=1;
@@ -233,64 +315,10 @@ int esp_print_decrypt_buffer_by_ikev2(netdissect_options *ndo,
 
        if(end <= ct) return 0;
 
-       ctx = EVP_CIPHER_CTX_new();
-       if (ctx == NULL)
-               return 0;
-       if (set_cipher_parameters(ctx, sa->evp, sa->secret, NULL) < 0) {
-               EVP_CIPHER_CTX_free(ctx);
-               (*ndo->ndo_warning)(ndo, "espkey init failed");
-               return 0;
-       }
-       if (set_cipher_parameters(ctx, NULL, NULL, iv) < 0) {
-               EVP_CIPHER_CTX_free(ctx);
-               (*ndo->ndo_warning)(ndo, "IV init failed");
-               return 0;
-       }
-
-       /*
-        * At least as I read RFC 5996 section 3.14, if the cipher
-        * has a block size of which the ciphertext's size must
-        * be a multiple, the payload must be padded to make that
-        * happen, so the ciphertext length must be a multiple of
-        * the block size.  Fail if that's not the case.
-        */
-       block_size = (unsigned int)EVP_CIPHER_CTX_block_size(ctx);
-       if ((ctlen % block_size) != 0) {
-               EVP_CIPHER_CTX_free(ctx);
-               (*ndo->ndo_warning)(ndo, "ciphertext size %u is not a multiple of the cipher block size %u",
-                   ctlen, block_size);
-               return 0;
-       }
-
-       /*
-        * Attempt to allocate a buffer for the decrypted data, because
-        * we can't decrypt on top of the input buffer.
-        */
-       ptlen = ctlen;
-       pt = (u_char *)malloc(ptlen);
-       if (pt == NULL) {
-               EVP_CIPHER_CTX_free(ctx);
-               (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
-                       "can't allocate memory for decryption buffer");
-       }
-
-       /*
-        * The size of the ciphertext handed to us is a multiple of the
-        * cipher block size, so we don't need to worry about padding.
-        */
-       if (!EVP_CIPHER_CTX_set_padding(ctx, 0)) {
-               free(pt);
-               EVP_CIPHER_CTX_free(ctx);
-               (*ndo->ndo_warning)(ndo, "EVP_CIPHER_CTX_set_padding failed");
+       pt = do_decrypt(ndo, "esp_print_decrypt_buffer_by_ikev2", sa, iv,
+           ct, ctlen);
+       if (pt == NULL)
                return 0;
-       }
-       if (!EVP_DecryptUpdate(ctx, pt, &len, ct, ctlen)) {
-               free(pt);
-               EVP_CIPHER_CTX_free(ctx);
-               (*ndo->ndo_warning)(ndo, "EVP_DecryptUpdate failed");
-               return 0;
-       }
-       EVP_CIPHER_CTX_free(ctx);
 
        /*
         * Switch to the output buffer for dissection, and save it
@@ -708,13 +736,9 @@ esp_print(netdissect_options *ndo,
        const struct ip6_hdr *ip6 = NULL;
        const u_char *iv;
        u_int ivlen;
+       u_int payloadlen;
        const u_char *ct;
-       u_int ctlen;
-       int len;
-       EVP_CIPHER_CTX *ctx;
-       unsigned int block_size;
        u_char *pt;
-       u_int ptlen;
        u_int padlen;
        u_int nh;
 #endif
@@ -825,7 +849,7 @@ esp_print(netdissect_options *ndo,
         * the beginning of the authentication data/integrity check
         * value, i.e. right past the end of the ciphertext;
         */
-       ctlen = ep - ct;
+       payloadlen = ep - ct;
 
        if (sa->evp == NULL)
                return;
@@ -842,81 +866,15 @@ esp_print(netdissect_options *ndo,
                return;
        }
 
-       ctx = EVP_CIPHER_CTX_new();
-       if (ctx == NULL) {
-               /*
-                * Failed to initialize the cipher context.
-                * From a look at the OpenSSL code, this appears to
-                * mean "couldn't allocate memory for the cipher context";
-                * note that we're not passing any parameters, so there's
-                * not much else it can mean.
-                */
-               (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
-                       "esp_print: can't allocate memory for cipher context");
-       }
-
-       if (set_cipher_parameters(ctx, sa->evp, sa->secret, NULL) < 0) {
-               EVP_CIPHER_CTX_free(ctx);
-               (*ndo->ndo_warning)(ndo, "espkey init failed");
-               return;
-       }
-
-       if (set_cipher_parameters(ctx, NULL, NULL, iv) < 0) {
-               EVP_CIPHER_CTX_free(ctx);
-               (*ndo->ndo_warning)(ndo, "IV init failed");
+       pt = do_decrypt(ndo, "esp_print", sa, iv, ct, payloadlen);
+       if (pt == NULL)
                return;
-       }
-
-       /*
-        * At least as I read RFC 4303 section 2.4, if the cipher
-        * has a block size of which the ciphertext's size must
-        * be a multiple, the payload must be padded to make that
-        * happen, so the ciphertext length must be a multiple of
-        * the block size.  Fail if that's not the case.
-        */
-       block_size = (unsigned int)EVP_CIPHER_CTX_block_size(ctx);
-       if ((ctlen % block_size) != 0) {
-               EVP_CIPHER_CTX_free(ctx);
-               (*ndo->ndo_warning)(ndo, "ciphertext size %u is not a multiple of the cipher block size %u",
-                   ctlen, block_size);
-               return;
-       }
-
-       /*
-        * Attempt to allocate a buffer for the decrypted data, because
-        * we can't decrypt on top of the input buffer.
-        */
-       ptlen = ctlen;
-       pt = (u_char *)malloc(ptlen);
-       if (pt == NULL) {
-               EVP_CIPHER_CTX_free(ctx);
-               (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
-                       "esp_print: can't allocate memory for decryption buffer");
-       }
-
-       /*
-        * The size of the ciphertext handed to us is a multiple of the
-        * cipher block size, so we don't need to worry about padding.
-        */
-       if (!EVP_CIPHER_CTX_set_padding(ctx, 0)) {
-               free(pt);
-               EVP_CIPHER_CTX_free(ctx);
-               (*ndo->ndo_warning)(ndo, "EVP_CIPHER_CTX_set_padding failed");
-               return;
-       }
-       if (!EVP_DecryptUpdate(ctx, pt, &len, ct, ctlen)) {
-               free(pt);
-               EVP_CIPHER_CTX_free(ctx);
-               (*ndo->ndo_warning)(ndo, "EVP_DecryptUpdate failed");
-               return;
-       }
-       EVP_CIPHER_CTX_free(ctx);
 
        /*
         * Switch to the output buffer for dissection, and
         * save it on the buffer stack so it can be freed.
         */
-       ep = pt + ptlen;
+       ep = pt + payloadlen;
        if (!nd_push_buffer(ndo, pt, pt, ep)) {
                free(pt);
                (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
@@ -933,7 +891,7 @@ esp_print(netdissect_options *ndo,
         * "plaintext" is not what was being sent.
         */
        padlen = GET_U_1(ep - 2);
-       if (padlen + 2 > ptlen) {
+       if (padlen + 2 > payloadlen) {
                nd_print_trunc(ndo);
                return;
        }
@@ -944,7 +902,7 @@ esp_print(netdissect_options *ndo,
        ND_PRINT(": ");
 
        /* Now dissect the plaintext. */
-       ip_print_demux(ndo, pt, ptlen - (padlen + 2), ver, fragmented,
+       ip_print_demux(ndo, pt, payloadlen - (padlen + 2), ver, fragmented,
            ttl_hl, nh, bp2);
 
        /* Pop the buffer, freeing it. */