int ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv, const u8 *crypt, u8 *plain, size_t len) { struct crypto_cipher *cipher; int encr_alg; switch (alg) { case ENCR_3DES: encr_alg = CRYPTO_CIPHER_ALG_3DES; break; case ENCR_AES_CBC: encr_alg = CRYPTO_CIPHER_ALG_AES; break; default: wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg); return -1; } cipher = crypto_cipher_init(encr_alg, iv, key, key_len); if (cipher == NULL) { wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher"); return -1; } if (crypto_cipher_decrypt(cipher, crypt, plain, len) < 0) { wpa_printf(MSG_INFO, "IKEV2: Decryption failed"); crypto_cipher_deinit(cipher); return -1; } crypto_cipher_deinit(cipher); return 0; }
//This method should be called ONLY by tsiServer or tsiClient TLS_SESSION_INFO extern "C" JNIEXPORT jint JNICALL Java_com_att_aro_pcap_AROCryptoAdapter_cryptocipherdecrypt (JNIEnv *env, jobject obj, jint pCipher, jbyteArray enc, jbyteArray _plain, jint enclength, jint objectType) { int ret = ARO_CRYPTO_ERROR; int i_pCipher = (int)pCipher; int i_enclength = (int)enclength; int i_objectType = (int)objectType; jbyte* encbuff = NULL; encbuff = env->GetByteArrayElements(enc, NULL); jbyte* _plainbuff = NULL; _plainbuff = env->GetByteArrayElements(_plain, NULL); if(!encbuff || !_plainbuff) return NULL; struct crypto_cipher* ctx = NULL; if(i_pCipher == CTX_TSI_CLIENT) { if(i_objectType == CTX_TSI_CLIENT) ctx = tsiclient_ctx_client; else ctx = tsiserver_ctx_client; } else { if(i_objectType == CTX_TSI_CLIENT) ctx = tsiclient_ctx_server; else ctx = tsiserver_ctx_server; } ret = crypto_cipher_decrypt(ctx, (BYTE*)encbuff, (BYTE*)_plainbuff, i_enclength); env->ReleaseByteArrayElements(enc, encbuff, 0); env->ReleaseByteArrayElements(_plain, _plainbuff, 0); return ret; }
/** Run unit tests for our AES functionality */ static void test_crypto_aes(void *arg) { char *data1 = NULL, *data2 = NULL, *data3 = NULL; crypto_cipher_t *env1 = NULL, *env2 = NULL; int i, j; char *mem_op_hex_tmp=NULL; int use_evp = !strcmp(arg,"evp"); evaluate_evp_for_aes(use_evp); evaluate_ctr_for_aes(); data1 = tor_malloc(1024); data2 = tor_malloc(1024); data3 = tor_malloc(1024); /* Now, test encryption and decryption with stream cipher. */ data1[0]='\0'; for (i = 1023; i>0; i -= 35) strncat(data1, "Now is the time for all good onions", i); memset(data2, 0, 1024); memset(data3, 0, 1024); env1 = crypto_cipher_new(NULL); test_neq_ptr(env1, 0); env2 = crypto_cipher_new(crypto_cipher_get_key(env1)); test_neq_ptr(env2, 0); /* Try encrypting 512 chars. */ crypto_cipher_encrypt(env1, data2, data1, 512); crypto_cipher_decrypt(env2, data3, data2, 512); test_memeq(data1, data3, 512); test_memneq(data1, data2, 512); /* Now encrypt 1 at a time, and get 1 at a time. */ for (j = 512; j < 560; ++j) { crypto_cipher_encrypt(env1, data2+j, data1+j, 1); } for (j = 512; j < 560; ++j) { crypto_cipher_decrypt(env2, data3+j, data2+j, 1); } test_memeq(data1, data3, 560); /* Now encrypt 3 at a time, and get 5 at a time. */ for (j = 560; j < 1024-5; j += 3) { crypto_cipher_encrypt(env1, data2+j, data1+j, 3); } for (j = 560; j < 1024-5; j += 5) { crypto_cipher_decrypt(env2, data3+j, data2+j, 5); } test_memeq(data1, data3, 1024-5); /* Now make sure that when we encrypt with different chunk sizes, we get the same results. */ crypto_cipher_free(env2); env2 = NULL; memset(data3, 0, 1024); env2 = crypto_cipher_new(crypto_cipher_get_key(env1)); test_neq_ptr(env2, NULL); for (j = 0; j < 1024-16; j += 17) { crypto_cipher_encrypt(env2, data3+j, data1+j, 17); } for (j= 0; j < 1024-16; ++j) { if (data2[j] != data3[j]) { printf("%d: %d\t%d\n", j, (int) data2[j], (int) data3[j]); } } test_memeq(data2, data3, 1024-16); crypto_cipher_free(env1); env1 = NULL; crypto_cipher_free(env2); env2 = NULL; /* NIST test vector for aes. */ /* IV starts at 0 */ env1 = crypto_cipher_new("\x80\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00"); crypto_cipher_encrypt(env1, data1, "\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00", 16); test_memeq_hex(data1, "0EDD33D3C621E546455BD8BA1418BEC8"); /* Now test rollover. All these values are originally from a python * script. */ crypto_cipher_free(env1); env1 = crypto_cipher_new_with_iv( "\x80\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\x00" "\xff\xff\xff\xff\xff\xff\xff\xff"); memset(data2, 0, 1024); crypto_cipher_encrypt(env1, data1, data2, 32); test_memeq_hex(data1, "335fe6da56f843199066c14a00a40231" "cdd0b917dbc7186908a6bfb5ffd574d3"); crypto_cipher_free(env1); env1 = crypto_cipher_new_with_iv( "\x80\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00\xff\xff\xff\xff" "\xff\xff\xff\xff\xff\xff\xff\xff"); memset(data2, 0, 1024); crypto_cipher_encrypt(env1, data1, data2, 32); test_memeq_hex(data1, "e627c6423fa2d77832a02b2794094b73" "3e63c721df790d2c6469cc1953a3ffac"); crypto_cipher_free(env1); env1 = crypto_cipher_new_with_iv( "\x80\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00", "\xff\xff\xff\xff\xff\xff\xff\xff" "\xff\xff\xff\xff\xff\xff\xff\xff"); memset(data2, 0, 1024); crypto_cipher_encrypt(env1, data1, data2, 32); test_memeq_hex(data1, "2aed2bff0de54f9328efd070bf48f70a" "0EDD33D3C621E546455BD8BA1418BEC8"); /* Now check rollover on inplace cipher. */ crypto_cipher_free(env1); env1 = crypto_cipher_new_with_iv( "\x80\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00", "\xff\xff\xff\xff\xff\xff\xff\xff" "\xff\xff\xff\xff\xff\xff\xff\xff"); crypto_cipher_crypt_inplace(env1, data2, 64); test_memeq_hex(data2, "2aed2bff0de54f9328efd070bf48f70a" "0EDD33D3C621E546455BD8BA1418BEC8" "93e2c5243d6839eac58503919192f7ae" "1908e67cafa08d508816659c2e693191"); crypto_cipher_free(env1); env1 = crypto_cipher_new_with_iv( "\x80\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00", "\xff\xff\xff\xff\xff\xff\xff\xff" "\xff\xff\xff\xff\xff\xff\xff\xff"); crypto_cipher_crypt_inplace(env1, data2, 64); test_assert(tor_mem_is_zero(data2, 64)); done: tor_free(mem_op_hex_tmp); if (env1) crypto_cipher_free(env1); if (env2) crypto_cipher_free(env2); tor_free(data1); tor_free(data2); tor_free(data3); }
/* Perform WEP decryption on given buffer. Buffer includes whole WEP part of * the frame: IV (4 bytes), encrypted payload (including SNAP header), * ICV (4 bytes). len includes both IV and ICV. * * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on * failure. If frame is OK, IV and ICV will be removed. */ static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) { struct prism2_wep_data *wep = priv; #if(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) struct blkcipher_desc desc = {.tfm = wep->rx_tfm}; #endif u32 klen, plen; u8 key[WEP_KEY_LEN + 3]; u8 keyidx, *pos; #ifndef JOHN_HWSEC u32 crc; u8 icv[4]; struct scatterlist sg; #endif if (skb->len < hdr_len + 8) return -1; pos = skb->data + hdr_len; key[0] = *pos++; key[1] = *pos++; key[2] = *pos++; keyidx = *pos++ >> 6; if (keyidx != wep->key_idx) return -1; klen = 3 + wep->key_len; /* Copy rest of the WEP key (the secret part) */ memcpy(key + 3, wep->key, wep->key_len); /* Apply RC4 to data and compute CRC32 over decrypted data */ plen = skb->len - hdr_len - 8; #ifndef JOHN_HWSEC #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) crypto_cipher_setkey(wep->tfm, key, klen); sg.page = virt_to_page(pos); sg.offset = offset_in_page(pos); sg.length = plen + 4; crypto_cipher_decrypt(wep->tfm, &sg, &sg, plen + 4); #else crypto_blkcipher_setkey(wep->rx_tfm, key, klen); #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) sg.page = virt_to_page(pos); sg.offset = offset_in_page(pos); sg.length = plen + 4; #else sg_init_one(&sg, pos, plen + 4); #endif if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) return -7; #endif #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) crc = ~crc32_le(~0, pos, plen); #else crc = ~ether_crc_le(plen, pos); #endif icv[0] = crc; icv[1] = crc >> 8; icv[2] = crc >> 16; icv[3] = crc >> 24; if (memcmp(icv, pos + plen, 4) != 0) { /* ICV mismatch - drop frame */ return -2; } #endif /* JOHN_HWSEC */ /* Remove IV and ICV */ memmove(skb->data + 4, skb->data, hdr_len); skb_pull(skb, 4); skb_trim(skb, skb->len - 4); return 0; } static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv) { struct prism2_wep_data *wep = priv; if (len < 0 || len > WEP_KEY_LEN) return -1; memcpy(wep->key, key, len); wep->key_len = len; return 0; } static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv) { struct prism2_wep_data *wep = priv; if (len < wep->key_len) return -1; memcpy(key, wep->key, wep->key_len); return wep->key_len; } static char * prism2_wep_print_stats(char *p, void *priv) { struct prism2_wep_data *wep = priv; p += sprintf(p, "key[%d] alg=WEP len=%d\n", wep->key_idx, wep->key_len); return p; } static struct ieee80211_crypto_ops ieee80211_crypt_wep = { .name = "WEP", .init = prism2_wep_init, .deinit = prism2_wep_deinit, .encrypt_mpdu = prism2_wep_encrypt, .decrypt_mpdu = prism2_wep_decrypt, .encrypt_msdu = NULL, .decrypt_msdu = NULL, .set_key = prism2_wep_set_key, .get_key = prism2_wep_get_key, .print_stats = prism2_wep_print_stats, .extra_prefix_len = 4, /* IV */ .extra_postfix_len = 4, /* ICV */ .owner = THIS_MODULE, }; int __init ieee80211_crypto_wep_init(void) { return ieee80211_register_crypto_ops(&ieee80211_crypt_wep); } void __exit ieee80211_crypto_wep_exit(void) { ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep); } void ieee80211_wep_null(void) { // printk("============>%s()\n", __FUNCTION__); return; } #if 0 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) EXPORT_SYMBOL(ieee80211_wep_null); #else EXPORT_SYMBOL_NOVERS(ieee80211_wep_null); #endif module_init(ieee80211_crypto_wep_init); module_exit(ieee80211_crypto_wep_exit);
/** * Try to decrypt the passphrase-encrypted blob of <b>input_len</b> bytes in * <b>input</b> using the passphrase <b>secret</b> of <b>secret_len</b> bytes. * On success, return 0 and allocate a new chunk of memory to hold the * decrypted data, and store a pointer to that memory in *<b>out</b>, and its * size in <b>outlen_out</b>. On failure, return UNPWBOX_BAD_SECRET if * the passphrase might have been wrong, and UNPWBOX_CORRUPT if the object is * definitely corrupt. */ int crypto_unpwbox(uint8_t **out, size_t *outlen_out, const uint8_t *inp, size_t input_len, const char *secret, size_t secret_len) { uint8_t *result = NULL; const uint8_t *encrypted; uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN]; uint8_t hmac[DIGEST256_LEN]; uint32_t result_len; size_t encrypted_len; crypto_cipher_t *cipher = NULL; int rv = UNPWBOX_CORRUPTED; ssize_t got_len; pwbox_encoded_t *enc = NULL; got_len = pwbox_encoded_parse(&enc, inp, input_len); if (got_len < 0 || (size_t)got_len != input_len) goto err; /* Now derive the keys and check the hmac. */ if (secret_to_key_derivekey(keys, sizeof(keys), pwbox_encoded_getarray_skey_header(enc), pwbox_encoded_getlen_skey_header(enc), secret, secret_len) < 0) goto err; crypto_hmac_sha256((char *)hmac, (const char*)keys + CIPHER_KEY_LEN, DIGEST256_LEN, (const char*)inp, input_len - DIGEST256_LEN); if (tor_memneq(hmac, enc->hmac, DIGEST256_LEN)) { rv = UNPWBOX_BAD_SECRET; goto err; } /* How long is the plaintext? */ encrypted = pwbox_encoded_getarray_data(enc); encrypted_len = pwbox_encoded_getlen_data(enc); if (encrypted_len < 4) goto err; cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv); crypto_cipher_decrypt(cipher, (char*)&result_len, (char*)encrypted, 4); result_len = ntohl(result_len); if (encrypted_len < result_len + 4) goto err; /* Allocate a buffer and decrypt */ result = tor_malloc_zero(result_len); crypto_cipher_decrypt(cipher, (char*)result, (char*)encrypted+4, result_len); *out = result; *outlen_out = result_len; rv = UNPWBOX_OKAY; goto out; err: tor_free(result); out: crypto_cipher_free(cipher); pwbox_encoded_free(enc); memwipe(keys, 0, sizeof(keys)); return rv; }
/* * Decompress (decrypt) an MPPE packet. */ static int mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf, int osize) { struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; unsigned ccount; int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED; int sanity = 0; struct scatterlist sg_in[1], sg_out[1]; if (isize <= PPP_HDRLEN + MPPE_OVHD) { if (state->debug) printk(KERN_DEBUG "mppe_decompress[%d]: short pkt (%d)\n", state->unit, isize); return DECOMP_ERROR; } /* * Make sure we have enough room to decrypt the packet. * Note that for our test we only subtract 1 byte whereas in * mppe_compress() we added 2 bytes (+MPPE_OVHD); * this is to account for possible PFC. */ if (osize < isize - MPPE_OVHD - 1) { printk(KERN_DEBUG "mppe_decompress[%d]: osize too small! " "(have: %d need: %d)\n", state->unit, osize, isize - MPPE_OVHD - 1); return DECOMP_ERROR; } osize = isize - MPPE_OVHD - 2; /* assume no PFC */ ccount = MPPE_CCOUNT(ibuf); if (state->debug >= 7) printk(KERN_DEBUG "mppe_decompress[%d]: ccount %d\n", state->unit, ccount); /* sanity checks -- terminate with extreme prejudice */ if (!(MPPE_BITS(ibuf) & MPPE_BIT_ENCRYPTED)) { printk(KERN_DEBUG "mppe_decompress[%d]: ENCRYPTED bit not set!\n", state->unit); state->sanity_errors += 100; sanity = 1; } if (!state->stateful && !flushed) { printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set in " "stateless mode!\n", state->unit); state->sanity_errors += 100; sanity = 1; } if (state->stateful && ((ccount & 0xff) == 0xff) && !flushed) { printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set on " "flag packet!\n", state->unit); state->sanity_errors += 100; sanity = 1; } if (sanity) { if (state->sanity_errors < SANITY_MAX) return DECOMP_ERROR; else /* * Take LCP down if the peer is sending too many bogons. * We don't want to do this for a single or just a few * instances since it could just be due to packet corruption. */ return DECOMP_FATALERROR; } /* * Check the coherency count. */ if (!state->stateful) { /* RFC 3078, sec 8.1. Rekey for every packet. */ while (state->ccount != ccount) { mppe_rekey(state, 0); state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; } } else { /* RFC 3078, sec 8.2. */ if (!state->discard) { /* normal state */ state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; if (ccount != state->ccount) { /* * (ccount > state->ccount) * Packet loss detected, enter the discard state. * Signal the peer to rekey (by sending a CCP Reset-Request). */ state->discard = 1; return DECOMP_ERROR; } } else { /* discard state */ if (!flushed) { /* ccp.c will be silent (no additional CCP Reset-Requests). */ return DECOMP_ERROR; } else { /* Rekey for every missed "flag" packet. */ while ((ccount & ~0xff) != (state->ccount & ~0xff)) { mppe_rekey(state, 0); state->ccount = (state->ccount + 256) % MPPE_CCOUNT_SPACE; } /* reset */ state->discard = 0; state->ccount = ccount; /* * Another problem with RFC 3078 here. It implies that the * peer need not send a Reset-Ack packet. But RFC 1962 * requires it. Hopefully, M$ does send a Reset-Ack; even * though it isn't required for MPPE synchronization, it is * required to reset CCP state. */ } } if (flushed) mppe_rekey(state, 0); } /* * Fill in the first part of the PPP header. The protocol field * comes from the decrypted data. */ obuf[0] = PPP_ADDRESS(ibuf); /* +1 */ obuf[1] = PPP_CONTROL(ibuf); /* +1 */ obuf += 2; ibuf += PPP_HDRLEN + MPPE_OVHD; isize -= PPP_HDRLEN + MPPE_OVHD; /* -6 */ /* net osize: isize-4 */ /* * Decrypt the first byte in order to check if it is * a compressed or uncompressed protocol field. */ setup_sg(sg_in, ibuf, 1); setup_sg(sg_out, obuf, 1); if (crypto_cipher_decrypt(state->arc4, sg_out, sg_in, 1) != 0) { printk(KERN_DEBUG "crypto_cypher_decrypt failed\n"); return DECOMP_ERROR; } /* * Do PFC decompression. * This would be nicer if we were given the actual sk_buff * instead of a char *. */ if ((obuf[0] & 0x01) != 0) { obuf[1] = obuf[0]; obuf[0] = 0; obuf++; osize++; } /* And finally, decrypt the rest of the packet. */ setup_sg(sg_in, ibuf + 1, isize - 1); setup_sg(sg_out, obuf + 1, osize - 1); if (crypto_cipher_decrypt(state->arc4, sg_out, sg_in, isize - 1) != 0) { printk(KERN_DEBUG "crypto_cypher_decrypt failed\n"); return DECOMP_ERROR; } state->stats.unc_bytes += osize; state->stats.unc_packets++; state->stats.comp_bytes += isize; state->stats.comp_packets++; /* good packet credit */ state->sanity_errors >>= 1; return osize; }
/** * tlsv1_record_receive - TLS record layer: Process a received message * @rl: Pointer to TLS record layer data * @in_data: Received data * @in_len: Length of the received data * @out_data: Buffer for output data (must be at least as long as in_data) * @out_len: Set to maximum out_data length by caller; used to return the * length of the used data * @alert: Buffer for returning an alert value on failure * Returns: 0 on success, -1 on failure * * This function decrypts the received message, verifies HMAC and TLS record * layer header. */ int tlsv1_record_receive(struct tlsv1_record_layer *rl, const u8 *in_data, size_t in_len, u8 *out_data, size_t *out_len, u8 *alert) { size_t i, rlen, hlen; u8 padlen; struct crypto_hash *hmac; u8 len[2], hash[100]; wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received", in_data, in_len); if (in_len < TLS_RECORD_HEADER_LEN) { wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu)", (unsigned long) in_len); *alert = TLS_ALERT_DECODE_ERROR; return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d " "length %d", in_data[0], in_data[1], in_data[2], WPA_GET_BE16(in_data + 3)); if (in_data[0] != TLS_CONTENT_TYPE_HANDSHAKE && in_data[0] != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC && in_data[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type 0x%x", in_data[0]); *alert = TLS_ALERT_UNEXPECTED_MESSAGE; return -1; } if (WPA_GET_BE16(in_data + 1) != TLS_VERSION) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version " "%d.%d", in_data[1], in_data[2]); *alert = TLS_ALERT_PROTOCOL_VERSION; return -1; } rlen = WPA_GET_BE16(in_data + 3); /* TLSCiphertext must not be more than 2^14+2048 bytes */ if (TLS_RECORD_HEADER_LEN + rlen > 18432) { wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)", (unsigned long) (TLS_RECORD_HEADER_LEN + rlen)); *alert = TLS_ALERT_RECORD_OVERFLOW; return -1; } in_data += TLS_RECORD_HEADER_LEN; in_len -= TLS_RECORD_HEADER_LEN; if (rlen > in_len) { wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included " "(rlen=%lu > in_len=%lu)", (unsigned long) rlen, (unsigned long) in_len); *alert = TLS_ALERT_DECODE_ERROR; return -1; } in_len = rlen; if (*out_len < in_len) { wpa_printf(MSG_DEBUG, "TLSv1: Not enough output buffer for " "processing received record"); *alert = TLS_ALERT_INTERNAL_ERROR; return -1; } os_memcpy(out_data, in_data, in_len); *out_len = in_len; if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) { if (crypto_cipher_decrypt(rl->read_cbc, out_data, out_data, in_len) < 0) { *alert = TLS_ALERT_DECRYPTION_FAILED; return -1; } if (rl->iv_size) { if (in_len == 0) { wpa_printf(MSG_DEBUG, "TLSv1: Too short record" " (no pad)"); *alert = TLS_ALERT_DECODE_ERROR; return -1; } padlen = out_data[in_len - 1]; if (padlen >= in_len) { wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad " "length (%u, in_len=%lu) in " "received record", padlen, (unsigned long) in_len); *alert = TLS_ALERT_DECRYPTION_FAILED; return -1; } for (i = in_len - padlen; i < in_len; i++) { if (out_data[i] != padlen) { wpa_hexdump(MSG_DEBUG, "TLSv1: Invalid pad in " "received record", out_data + in_len - padlen, padlen); *alert = TLS_ALERT_DECRYPTION_FAILED; return -1; } } *out_len -= padlen + 1; } wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Decrypted data", out_data, in_len); if (*out_len < rl->hash_size) { wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no " "hash value"); *alert = TLS_ALERT_INTERNAL_ERROR; return -1; } *out_len -= rl->hash_size; hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret, rl->hash_size); if (hmac == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " "to initialize HMAC"); *alert = TLS_ALERT_INTERNAL_ERROR; return -1; } crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN); /* type + version + length + fragment */ crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3); WPA_PUT_BE16(len, *out_len); crypto_hash_update(hmac, len, 2); crypto_hash_update(hmac, out_data, *out_len); hlen = sizeof(hash); if (crypto_hash_finish(hmac, hash, &hlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " "to calculate HMAC"); return -1; } if (hlen != rl->hash_size || os_memcmp(hash, out_data + *out_len, hlen) != 0) { wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in " "received message"); *alert = TLS_ALERT_BAD_RECORD_MAC; return -1; } } /* TLSCompressed must not be more than 2^14+1024 bytes */ if (TLS_RECORD_HEADER_LEN + *out_len > 17408) { wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)", (unsigned long) (TLS_RECORD_HEADER_LEN + *out_len)); *alert = TLS_ALERT_RECORD_OVERFLOW; return -1; } inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN); return 0; }
/* * Note: detecting truncated vs. non-truncated authentication data is very * expensive, so we only support truncated data, which is the recommended * and common case. */ int esp_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb) { struct iphdr *iph; struct ip_esp_hdr *esph; struct esp_data *esp = x->data; struct sk_buff *trailer; int blksize = crypto_tfm_alg_blocksize(esp->conf.tfm); int alen = esp->auth.icv_trunc_len; int elen = skb->len - sizeof(struct ip_esp_hdr) - esp->conf.ivlen - alen; int nfrags; int encap_len = 0; if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr))) goto out; if (elen <= 0 || (elen & (blksize-1))) goto out; /* If integrity check is required, do this. */ if (esp->auth.icv_full_len) { u8 sum[esp->auth.icv_full_len]; u8 sum1[alen]; esp->auth.icv(esp, skb, 0, skb->len-alen, sum); if (skb_copy_bits(skb, skb->len-alen, sum1, alen)) BUG(); if (unlikely(memcmp(sum, sum1, alen))) { x->stats.integrity_failed++; goto out; } } if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0) goto out; skb->ip_summed = CHECKSUM_NONE; esph = (struct ip_esp_hdr*)skb->data; iph = skb->nh.iph; /* Get ivec. This can be wrong, check against another impls. */ if (esp->conf.ivlen) crypto_cipher_set_iv(esp->conf.tfm, esph->enc_data, crypto_tfm_alg_ivsize(esp->conf.tfm)); { u8 nexthdr[2]; struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags]; struct scatterlist *sg = sgbuf; u8 workbuf[60]; int padlen; if (unlikely(nfrags > MAX_SG_ONSTACK)) { sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); if (!sg) goto out; } skb_to_sgvec(skb, sg, sizeof(struct ip_esp_hdr) + esp->conf.ivlen, elen); crypto_cipher_decrypt(esp->conf.tfm, sg, sg, elen); if (unlikely(sg != sgbuf)) kfree(sg); if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) BUG(); padlen = nexthdr[0]; if (padlen+2 >= elen) goto out; /* ... check padding bits here. Silly. :-) */ if (x->encap && decap && decap->decap_type) { struct esp_decap_data *encap_data; struct udphdr *uh = (struct udphdr *) (iph+1); encap_data = (struct esp_decap_data *) (decap->decap_data); encap_data->proto = 0; switch (decap->decap_type) { case UDP_ENCAP_ESPINUDP: if ((void*)uh == (void*)esph) { printk(KERN_DEBUG "esp_input(): Got ESP; expecting ESPinUDP\n"); break; } encap_data->proto = AF_INET; encap_data->saddr.a4 = iph->saddr; encap_data->sport = uh->source; encap_len = (void*)esph - (void*)uh; if (encap_len != sizeof(*uh)) printk(KERN_DEBUG "esp_input(): UDP -> ESP: too much room: %d\n", encap_len); break; default: printk(KERN_INFO "esp_input(): processing unknown encap type: %u\n", decap->decap_type); break; } } iph->protocol = nexthdr[1]; pskb_trim(skb, skb->len - alen - padlen - 2); memcpy(workbuf, skb->nh.raw, iph->ihl*4); skb->h.raw = skb_pull(skb, sizeof(struct ip_esp_hdr) + esp->conf.ivlen); skb->nh.raw += encap_len + sizeof(struct ip_esp_hdr) + esp->conf.ivlen; memcpy(skb->nh.raw, workbuf, iph->ihl*4); skb->nh.iph->tot_len = htons(skb->len); } return 0; out: return -EINVAL; }
static int esp6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb) { struct ipv6hdr *iph; struct ipv6_esp_hdr *esph; struct esp_data *esp = x->data; struct sk_buff *trailer; int blksize = ALIGN(crypto_tfm_alg_blocksize(esp->conf.tfm), 4); int alen = esp->auth.icv_trunc_len; int elen = skb->len - sizeof(struct ipv6_esp_hdr) - esp->conf.ivlen - alen; int hdr_len = skb->h.raw - skb->nh.raw; int nfrags; unsigned char *tmp_hdr = NULL; int ret = 0; if (!pskb_may_pull(skb, sizeof(struct ipv6_esp_hdr))) { ret = -EINVAL; goto out_nofree; } esph = (struct ipv6_esp_hdr*)skb->data; if (elen <= 0 || (elen & (blksize-1))) { ret = -EINVAL; goto out_nofree; } tmp_hdr = kmalloc(hdr_len, GFP_ATOMIC); if (!tmp_hdr) { ret = -ENOMEM; goto out_nofree; } memcpy(tmp_hdr, skb->nh.raw, hdr_len); /* If integrity check is required, do this. */ if (esp->auth.icv_full_len) { u8 sum[esp->auth.icv_full_len]; u8 sum1[alen]; if (x->props.replay_window && xfrm_replay_check(x, esph->seq_no)) { ret = -EINVAL; goto out; } esp->auth.icv(esp, skb, 0, skb->len-alen, sum); if (skb_copy_bits(skb, skb->len-alen, sum1, alen)) BUG(); if (unlikely(memcmp(sum, sum1, alen))) { x->stats.integrity_failed++; ret = -EINVAL; goto out; } if (x->props.replay_window) xfrm_replay_advance(x, esph->seq_no); } if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0) { ret = -EINVAL; goto out; } skb->ip_summed = CHECKSUM_NONE; iph = skb->nh.ipv6h; /* Get ivec. This can be wrong, check against another impls. */ if (esp->conf.ivlen) crypto_cipher_set_iv(esp->conf.tfm, esph->enc_data, crypto_tfm_alg_ivsize(esp->conf.tfm)); { u8 nexthdr[2]; struct scatterlist *sg = &esp->sgbuf[0]; u8 padlen; if (unlikely(nfrags > ESP_NUM_FAST_SG)) { sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); if (!sg) { ret = -ENOMEM; goto out; } } skb_to_sgvec(skb, sg, sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen, elen); crypto_cipher_decrypt(esp->conf.tfm, sg, sg, elen); if (unlikely(sg != &esp->sgbuf[0])) kfree(sg); if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) BUG(); padlen = nexthdr[0]; if (padlen+2 >= elen) { LIMIT_NETDEBUG(KERN_WARNING "ipsec esp packet is garbage padlen=%d, elen=%d\n", padlen+2, elen); ret = -EINVAL; goto out; } /* ... check padding bits here. Silly. :-) */ pskb_trim(skb, skb->len - alen - padlen - 2); skb->h.raw = skb_pull(skb, sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen); skb->nh.raw += sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen; memcpy(skb->nh.raw, tmp_hdr, hdr_len); skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); ret = nexthdr[1]; } out: kfree(tmp_hdr); out_nofree: return ret; }
int ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv, const u8 *crypt, u8 *plain, size_t len) { struct crypto_cipher *cipher; int encr_alg; #ifdef CCNS_PL if (alg == ENCR_3DES) { struct des3_key_s des3key; size_t i, blocks; /* ECB mode is used incorrectly for 3DES!? */ if (key_len != 24) { wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length"); return -1; } des3_key_setup(key, &des3key); if (len % 8) { wpa_printf(MSG_INFO, "IKEV2: Invalid encrypted " "length"); return -1; } blocks = len / 8; for (i = 0; i < blocks; i++) { des3_decrypt(crypt, &des3key, plain); plain += 8; crypt += 8; } } else { #endif /* CCNS_PL */ switch (alg) { case ENCR_3DES: encr_alg = CRYPTO_CIPHER_ALG_3DES; break; case ENCR_AES_CBC: encr_alg = CRYPTO_CIPHER_ALG_AES; break; default: wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg); return -1; } cipher = crypto_cipher_init(encr_alg, iv, key, key_len); if (cipher == NULL) { wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher"); return -1; } if (crypto_cipher_decrypt(cipher, crypt, plain, len) < 0) { wpa_printf(MSG_INFO, "IKEV2: Decryption failed"); crypto_cipher_deinit(cipher); return -1; } crypto_cipher_deinit(cipher); #ifdef CCNS_PL } #endif /* CCNS_PL */ return 0; }
/* * Note: detecting truncated vs. non-truncated authentication data is very * expensive, so we only support truncated data, which is the recommended * and common case. */ static int esp_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb) { struct iphdr *iph; struct ip_esp_hdr *esph; struct esp_data *esp = x->data; struct sk_buff *trailer; int blksize = ALIGN(crypto_tfm_alg_blocksize(esp->conf.tfm), 4); int alen = esp->auth.icv_trunc_len; int elen = skb->len - sizeof(struct ip_esp_hdr) - esp->conf.ivlen - alen; int nfrags; int encap_len = 0; u8 nexthdr[2]; struct scatterlist *sg; u8 workbuf[60]; int padlen; if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr))) goto out; esph = (struct ip_esp_hdr*)skb->data; if (elen <= 0 || (elen & (blksize-1))) goto out; /* If integrity check is required, do this. */ if (esp->auth.icv_full_len) { u8 sum[esp->auth.icv_full_len]; u8 sum1[alen]; if (x->props.replay_window && xfrm_replay_check(x, esph->seq_no)) goto out; esp->auth.icv(esp, skb, 0, skb->len-alen, sum); if (skb_copy_bits(skb, skb->len-alen, sum1, alen)) BUG(); if (unlikely(memcmp(sum, sum1, alen))) { x->stats.integrity_failed++; goto out; } if (x->props.replay_window) xfrm_replay_advance(x, esph->seq_no); } if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0) goto out; skb->ip_summed = CHECKSUM_NONE; iph = skb->nh.iph; /* Get ivec. This can be wrong, check against another impls. */ if (esp->conf.ivlen) crypto_cipher_set_iv(esp->conf.tfm, esph->enc_data, crypto_tfm_alg_ivsize(esp->conf.tfm)); sg = &esp->sgbuf[0]; if (unlikely(nfrags > ESP_NUM_FAST_SG)) { sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); if (!sg) goto out; } skb_to_sgvec(skb, sg, sizeof(struct ip_esp_hdr) + esp->conf.ivlen, elen); crypto_cipher_decrypt(esp->conf.tfm, sg, sg, elen); if (unlikely(sg != &esp->sgbuf[0])) kfree(sg); if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) BUG(); padlen = nexthdr[0]; if (padlen+2 >= elen) goto out; /* ... check padding bits here. Silly. :-) */ if (x->encap) { struct xfrm_encap_tmpl *encap = x->encap; struct udphdr *uh; if (encap->encap_type != decap->decap_type) goto out; uh = (struct udphdr *)(iph + 1); encap_len = (void*)esph - (void*)uh; /* * 1) if the NAT-T peer's IP or port changed then * advertize the change to the keying daemon. * This is an inbound SA, so just compare * SRC ports. */ if (iph->saddr != x->props.saddr.a4 || uh->source != encap->encap_sport) { xfrm_address_t ipaddr; ipaddr.a4 = iph->saddr; km_new_mapping(x, &ipaddr, uh->source); /* XXX: perhaps add an extra * policy check here, to see * if we should allow or * reject a packet from a * different source * address/port. */ } /* * 2) ignore UDP/TCP checksums in case * of NAT-T in Transport Mode, or * perform other post-processing fixes * as per draft-ietf-ipsec-udp-encaps-06, * section 3.1.2 */ if (!x->props.mode) skb->ip_summed = CHECKSUM_UNNECESSARY; } iph->protocol = nexthdr[1]; pskb_trim(skb, skb->len - alen - padlen - 2); memcpy(workbuf, skb->nh.raw, iph->ihl*4); skb->h.raw = skb_pull(skb, sizeof(struct ip_esp_hdr) + esp->conf.ivlen); skb->nh.raw += encap_len + sizeof(struct ip_esp_hdr) + esp->conf.ivlen; memcpy(skb->nh.raw, workbuf, iph->ihl*4); skb->nh.iph->tot_len = htons(skb->len); return 0; out: return -EINVAL; }
/** Decrypt the encrypted introduction points in <b>ipos_encrypted</b> of * length <b>ipos_encrypted_size</b> using <b>descriptor_cookie</b> and * write the result to a newly allocated string that is pointed to by * <b>ipos_decrypted</b> and its length to <b>ipos_decrypted_size</b>. * Return 0 if decryption was successful and -1 otherwise. */ int rend_decrypt_introduction_points(char **ipos_decrypted, size_t *ipos_decrypted_size, const char *descriptor_cookie, const char *ipos_encrypted, size_t ipos_encrypted_size) { tor_assert(ipos_encrypted); tor_assert(descriptor_cookie); if (ipos_encrypted_size < 2) { log_warn(LD_REND, "Size of encrypted introduction points is too " "small."); return -1; } if (ipos_encrypted[0] == (int)REND_BASIC_AUTH) { char iv[CIPHER_IV_LEN], client_id[REND_BASIC_AUTH_CLIENT_ID_LEN], session_key[CIPHER_KEY_LEN], *dec; int declen, client_blocks; size_t pos = 0, len, client_entries_len; crypto_digest_t *digest; crypto_cipher_t *cipher; client_blocks = (int) ipos_encrypted[1]; client_entries_len = client_blocks * REND_BASIC_AUTH_CLIENT_MULTIPLE * REND_BASIC_AUTH_CLIENT_ENTRY_LEN; if (ipos_encrypted_size < 2 + client_entries_len + CIPHER_IV_LEN + 1) { log_warn(LD_REND, "Size of encrypted introduction points is too " "small."); return -1; } memcpy(iv, ipos_encrypted + 2 + client_entries_len, CIPHER_IV_LEN); digest = crypto_digest_new(); crypto_digest_add_bytes(digest, descriptor_cookie, REND_DESC_COOKIE_LEN); crypto_digest_add_bytes(digest, iv, CIPHER_IV_LEN); crypto_digest_get_digest(digest, client_id, REND_BASIC_AUTH_CLIENT_ID_LEN); crypto_digest_free(digest); for (pos = 2; pos < 2 + client_entries_len; pos += REND_BASIC_AUTH_CLIENT_ENTRY_LEN) { if (tor_memeq(ipos_encrypted + pos, client_id, REND_BASIC_AUTH_CLIENT_ID_LEN)) { /* Attempt to decrypt introduction points. */ cipher = crypto_cipher_new(descriptor_cookie); if (crypto_cipher_decrypt(cipher, session_key, ipos_encrypted + pos + REND_BASIC_AUTH_CLIENT_ID_LEN, CIPHER_KEY_LEN) < 0) { log_warn(LD_REND, "Could not decrypt session key for client."); crypto_cipher_free(cipher); return -1; } crypto_cipher_free(cipher); len = ipos_encrypted_size - 2 - client_entries_len - CIPHER_IV_LEN; dec = tor_malloc_zero(len + 1); declen = crypto_cipher_decrypt_with_iv(session_key, dec, len, ipos_encrypted + 2 + client_entries_len, ipos_encrypted_size - 2 - client_entries_len); if (declen < 0) { log_warn(LD_REND, "Could not decrypt introduction point string."); tor_free(dec); return -1; } if (fast_memcmpstart(dec, declen, "introduction-point ")) { log_warn(LD_REND, "Decrypted introduction points don't " "look like we could parse them."); tor_free(dec); continue; } *ipos_decrypted = dec; *ipos_decrypted_size = declen; return 0; } } log_warn(LD_REND, "Could not decrypt introduction points. Please " "check your authorization for this service!"); return -1; } else if (ipos_encrypted[0] == (int)REND_STEALTH_AUTH) { char *dec; int declen; if (ipos_encrypted_size < CIPHER_IV_LEN + 2) { log_warn(LD_REND, "Size of encrypted introduction points is too " "small."); return -1; } dec = tor_malloc_zero(ipos_encrypted_size - CIPHER_IV_LEN - 1 + 1); declen = crypto_cipher_decrypt_with_iv(descriptor_cookie, dec, ipos_encrypted_size - CIPHER_IV_LEN - 1, ipos_encrypted + 1, ipos_encrypted_size - 1); if (declen < 0) { log_warn(LD_REND, "Decrypting introduction points failed!"); tor_free(dec); return -1; } *ipos_decrypted = dec; *ipos_decrypted_size = declen; return 0; } else { log_warn(LD_REND, "Unknown authorization type number: %d", ipos_encrypted[0]); return -1; } }
/** * tlsv1_record_receive - TLS record layer: Process a received message * @rl: Pointer to TLS record layer data * @in_data: Received data * @in_len: Length of the received data * @out_data: Buffer for output data (must be at least as long as in_data) * @out_len: Set to maximum out_data length by caller; used to return the * length of the used data * @alert: Buffer for returning an alert value on failure * Returns: 0 on success, -1 on failure * * This function decrypts the received message, verifies HMAC and TLS record * layer header. */ int tlsv1_record_receive(struct tlsv1_record_layer *rl, const u8 *in_data, size_t in_len, u8 *out_data, size_t *out_len, u8 *alert) { size_t i, rlen, hlen; u8 padlen; struct crypto_hash *hmac; u8 len[2], hash[100]; int force_mac_error = 0; wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received", in_data, in_len); if (in_len < TLS_RECORD_HEADER_LEN) { wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu)", (unsigned long) in_len); *alert = TLS_ALERT_DECODE_ERROR; return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d " "length %d", in_data[0], in_data[1], in_data[2], WPA_GET_BE16(in_data + 3)); if (in_data[0] != TLS_CONTENT_TYPE_HANDSHAKE && in_data[0] != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC && in_data[0] != TLS_CONTENT_TYPE_ALERT && in_data[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type 0x%x", in_data[0]); *alert = TLS_ALERT_UNEXPECTED_MESSAGE; return -1; } /* * TLS v1.0 and v1.1 RFCs were not exactly clear on the use of the * protocol version in record layer. As such, accept any {03,xx} value * to remain compatible with existing implementations. */ if (in_data[1] != 0x03) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version " "%u.%u", in_data[1], in_data[2]); *alert = TLS_ALERT_PROTOCOL_VERSION; return -1; } rlen = WPA_GET_BE16(in_data + 3); /* TLSCiphertext must not be more than 2^14+2048 bytes */ if (TLS_RECORD_HEADER_LEN + rlen > 18432) { wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)", (unsigned long) (TLS_RECORD_HEADER_LEN + rlen)); *alert = TLS_ALERT_RECORD_OVERFLOW; return -1; } in_data += TLS_RECORD_HEADER_LEN; in_len -= TLS_RECORD_HEADER_LEN; if (rlen > in_len) { wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included " "(rlen=%lu > in_len=%lu)", (unsigned long) rlen, (unsigned long) in_len); *alert = TLS_ALERT_DECODE_ERROR; return -1; } in_len = rlen; if (*out_len < in_len) { wpa_printf(MSG_DEBUG, "TLSv1: Not enough output buffer for " "processing received record"); *alert = TLS_ALERT_INTERNAL_ERROR; return -1; } if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) { size_t plen; if (crypto_cipher_decrypt(rl->read_cbc, in_data, out_data, in_len) < 0) { *alert = TLS_ALERT_DECRYPTION_FAILED; return -1; } plen = in_len; wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - Decrypted " "data", out_data, plen); if (rl->iv_size) { /* * TLS v1.0 defines different alert values for various * failures. That may information to aid in attacks, so * use the same bad_record_mac alert regardless of the * issues. * * In addition, instead of returning immediately on * error, run through the MAC check to make timing * attacks more difficult. */ if (rl->tls_version == TLS_VERSION_1_1) { /* Remove opaque IV[Cipherspec.block_length] */ if (plen < rl->iv_size) { wpa_printf(MSG_DEBUG, "TLSv1.1: Not " "enough room for IV"); force_mac_error = 1; goto check_mac; } os_memmove(out_data, out_data + rl->iv_size, plen - rl->iv_size); plen -= rl->iv_size; } /* Verify and remove padding */ if (plen == 0) { wpa_printf(MSG_DEBUG, "TLSv1: Too short record" " (no pad)"); force_mac_error = 1; goto check_mac; } padlen = out_data[plen - 1]; if (padlen >= plen) { wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad " "length (%u, plen=%lu) in " "received record", padlen, (unsigned long) plen); force_mac_error = 1; goto check_mac; } for (i = plen - padlen; i < plen; i++) { if (out_data[i] != padlen) { wpa_hexdump(MSG_DEBUG, "TLSv1: Invalid pad in " "received record", out_data + plen - padlen, padlen); force_mac_error = 1; goto check_mac; } } plen -= padlen + 1; } check_mac: wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - Decrypted " "data with IV and padding removed", out_data, plen); if (plen < rl->hash_size) { wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no " "hash value"); *alert = TLS_ALERT_BAD_RECORD_MAC; return -1; } plen -= rl->hash_size; hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret, rl->hash_size); if (hmac == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " "to initialize HMAC"); *alert = TLS_ALERT_INTERNAL_ERROR; return -1; } crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN); /* type + version + length + fragment */ crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3); WPA_PUT_BE16(len, plen); crypto_hash_update(hmac, len, 2); crypto_hash_update(hmac, out_data, plen); hlen = sizeof(hash); if (crypto_hash_finish(hmac, hash, &hlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " "to calculate HMAC"); *alert = TLS_ALERT_INTERNAL_ERROR; return -1; } if (hlen != rl->hash_size || os_memcmp(hash, out_data + plen, hlen) != 0 || force_mac_error) { wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in " "received message (force_mac_error=%d)", force_mac_error); *alert = TLS_ALERT_BAD_RECORD_MAC; return -1; } *out_len = plen; } else { os_memcpy(out_data, in_data, in_len); *out_len = in_len; } /* TLSCompressed must not be more than 2^14+1024 bytes */ if (TLS_RECORD_HEADER_LEN + *out_len > 17408) { wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)", (unsigned long) (TLS_RECORD_HEADER_LEN + *out_len)); *alert = TLS_ALERT_RECORD_OVERFLOW; return -1; } inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN); return 0; }