diff options
author | Guy Harris <guy@alum.mit.edu> | 2020-01-05 19:25:00 -0800 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2020-01-05 19:25:00 -0800 |
commit | fba80a0b8381e19d69c4121ca91a35da0abf0ec4 (patch) | |
tree | 25267d56e5705705a6df84f4d75d2e83e41e08d9 /print-esp.c | |
parent | bd22f1fd9a711831d04f568e26fc14048ff3157a (diff) | |
download | tcpdump-fba80a0b8381e19d69c4121ca91a35da0abf0ec4.tar.gz |
Put the crypto stuff into a common routine.
That makes it easier to 1) change it and 2) use different crypto
libraries for it.
Diffstat (limited to 'print-esp.c')
-rw-r--r-- | print-esp.c | 234 |
1 files changed, 96 insertions, 138 deletions
diff --git a/print-esp.c b/print-esp.c index ae8cb038..844522ec 100644 --- a/print-esp.c +++ b/print-esp.c @@ -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. */ |