int _gnutls_decrypt_pbes1_des_md5_data(const char *password, unsigned password_len, const struct pbkdf2_params *kdf_params, const struct pbe_enc_params *enc_params, gnutls_datum_t *encrypted_data, /* we re-use it */ gnutls_datum_t *decrypted_data) { int result; gnutls_datum_t dkey, d_iv; cipher_hd_st ch; uint8_t key[16]; const unsigned block_size = 8; if (enc_params->cipher != GNUTLS_CIPHER_DES_CBC) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); if (encrypted_data->size % block_size != 0) return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); /* generate the key */ pbkdf1_md5(password, password_len, kdf_params->salt, kdf_params->iter_count, sizeof(key), key); dkey.data = key; dkey.size = 8; d_iv.data = &key[8]; d_iv.size = 8; result = _gnutls_cipher_init(&ch, cipher_to_entry(GNUTLS_CIPHER_DES_CBC), &dkey, &d_iv, 0); if (result < 0) return gnutls_assert_val(result); result = _gnutls_cipher_decrypt(&ch, encrypted_data->data, encrypted_data->size); if (result < 0) { gnutls_assert(); goto error; } if ((int)encrypted_data->size - encrypted_data->data[encrypted_data->size - 1] < 0) { gnutls_assert(); result = GNUTLS_E_ILLEGAL_PARAMETER; goto error; } decrypted_data->data = encrypted_data->data; decrypted_data->size = encrypted_data->size - encrypted_data->data[encrypted_data->size - 1]; result = 0; error: _gnutls_cipher_deinit(&ch); return result; }
/* Auth_cipher API */ int _gnutls_auth_cipher_init(auth_cipher_hd_st * handle, const cipher_entry_st * e, const gnutls_datum_t * cipher_key, const gnutls_datum_t * iv, const mac_entry_st * me, const gnutls_datum_t * mac_key, unsigned etm, unsigned ssl_hmac, int enc) { int ret; if (unlikely(e == NULL)) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); FAIL_IF_LIB_ERROR; memset(handle, 0, sizeof(*handle)); handle->etm = etm; if (e->id != GNUTLS_CIPHER_NULL) { handle->non_null = 1; ret = _gnutls_cipher_init(&handle->cipher, e, cipher_key, iv, enc); if (ret < 0) return gnutls_assert_val(ret); } else handle->non_null = 0; if (me->id != GNUTLS_MAC_AEAD) { handle->is_mac = 1; handle->ssl_hmac = ssl_hmac; if (ssl_hmac) ret = _gnutls_mac_init_ssl3(&handle->mac.dig, me, mac_key->data, mac_key->size); else ret = _gnutls_mac_init(&handle->mac.mac, me, mac_key->data, mac_key->size); if (ret < 0) { gnutls_assert(); goto cleanup; } handle->tag_size = _gnutls_mac_get_algo_len(me); } else if (_gnutls_cipher_algo_is_aead(e)) { handle->tag_size = _gnutls_cipher_get_tag_size(e); } else { gnutls_assert(); ret = GNUTLS_E_INVALID_REQUEST; goto cleanup; } return 0; cleanup: if (handle->non_null != 0) _gnutls_cipher_deinit(&handle->cipher); return ret; }
int _gnutls_encrypt_session_ticket(gnutls_session_t session, const gnutls_datum_t *state, gnutls_datum_t *ticket_data) { cipher_hd_st cipher_hd; gnutls_datum_t IV; gnutls_datum_t encrypted_state = {NULL,0}; uint8_t iv[TICKET_IV_SIZE]; gnutls_datum_t stek_cipher_key, stek_mac_key, stek_key_name; struct ticket_st ticket; int ret; encrypted_state.size = ((state->size + TICKET_BLOCK_SIZE - 1) / TICKET_BLOCK_SIZE) * TICKET_BLOCK_SIZE; ticket_data->size = TICKET_KEY_NAME_SIZE + TICKET_IV_SIZE + 2 + encrypted_state.size + TICKET_MAC_SIZE; ticket_data->data = gnutls_calloc(1, ticket_data->size); if (!ticket_data->data) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } encrypted_state.data = ticket_data->data + TICKET_KEY_NAME_SIZE + TICKET_IV_SIZE + 2; memcpy(encrypted_state.data, state->data, state->size); /* Retrieve ticket encryption keys */ if (_gnutls_get_session_ticket_encryption_key(session, &stek_key_name, &stek_mac_key, &stek_cipher_key) < 0) { ret = GNUTLS_E_ENCRYPTION_FAILED; goto cleanup; } /* Encrypt state */ IV.data = iv; IV.size = TICKET_IV_SIZE; ret = gnutls_rnd(GNUTLS_RND_NONCE, iv, TICKET_IV_SIZE); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_cipher_init(&cipher_hd, cipher_to_entry(TICKET_CIPHER), &stek_cipher_key, &IV, 1); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_cipher_encrypt(&cipher_hd, encrypted_state.data, encrypted_state.size); if (ret < 0) { gnutls_assert(); goto cleanup2; } /* Fill the ticket structure to compute MAC. */ memcpy(ticket.key_name, stek_key_name.data, stek_key_name.size); memcpy(ticket.IV, IV.data, IV.size); ticket.encrypted_state_len = encrypted_state.size; ticket.encrypted_state = encrypted_state.data; ret = digest_ticket(&stek_mac_key, &ticket, ticket.mac); if (ret < 0) { gnutls_assert(); goto cleanup2; } encrypted_state.data = NULL; pack_ticket(&ticket, ticket_data); ret = 0; cleanup2: _gnutls_cipher_deinit(&cipher_hd); cleanup: _gnutls_free_datum(&encrypted_state); return ret; }
int _gnutls_decrypt_session_ticket(gnutls_session_t session, const gnutls_datum_t *ticket_data, gnutls_datum_t *state) { cipher_hd_st cipher_hd; gnutls_datum_t IV; gnutls_datum_t stek_key_name, stek_cipher_key, stek_mac_key; uint8_t cmac[TICKET_MAC_SIZE]; struct ticket_st ticket; int ret; /* callers must have that checked */ assert(!(session->internals.flags & GNUTLS_NO_TICKETS)); /* Retrieve ticket decryption keys */ if (_gnutls_get_session_ticket_decryption_key(session, ticket_data, &stek_key_name, &stek_mac_key, &stek_cipher_key) < 0) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); ret = unpack_ticket(ticket_data, &ticket); if (ret < 0) return ret; /* If the key name of the ticket does not match the one that is currently active, issue a new ticket. */ if (memcmp (ticket.key_name, stek_key_name.data, stek_key_name.size)) { ret = GNUTLS_E_DECRYPTION_FAILED; goto cleanup; } /* Check the integrity of ticket */ ret = digest_ticket(&stek_mac_key, &ticket, cmac); if (ret < 0) { gnutls_assert(); goto cleanup; } if (memcmp(ticket.mac, cmac, TICKET_MAC_SIZE)) { ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); goto cleanup; } if (ticket.encrypted_state_len % TICKET_BLOCK_SIZE != 0) { ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); goto cleanup; } /* Decrypt encrypted_state */ IV.data = ticket.IV; IV.size = TICKET_IV_SIZE; ret = _gnutls_cipher_init(&cipher_hd, cipher_to_entry(TICKET_CIPHER), &stek_cipher_key, &IV, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_cipher_decrypt(&cipher_hd, ticket.encrypted_state, ticket.encrypted_state_len); if (ret < 0) { gnutls_assert(); goto cleanup2; } state->data = ticket.encrypted_state; state->size = ticket.encrypted_state_len; ticket.encrypted_state = NULL; ret = 0; cleanup2: _gnutls_cipher_deinit(&cipher_hd); cleanup: deinit_ticket(&ticket); return ret; }
/* Initializes the write connection session * (write encrypted data) */ int _gnutls_write_connection_state_init (gnutls_session_t session) { int mac_size; int rc; _gnutls_uint64zero (session->connection_state.write_sequence_number); /* Update internals from CipherSuite selected. * If we are resuming just copy the connection session */ if (session->internals.resumed == RESUME_FALSE) { rc = _gnutls_set_write_cipher (session, _gnutls_cipher_suite_get_cipher_algo (&session->security_parameters. current_cipher_suite)); if (rc < 0) return rc; rc = _gnutls_set_write_mac (session, _gnutls_cipher_suite_get_mac_algo (&session->security_parameters. current_cipher_suite)); if (rc < 0) return rc; rc = _gnutls_set_kx (session, _gnutls_cipher_suite_get_kx_algo (&session->security_parameters. current_cipher_suite)); if (rc < 0) return rc; rc = _gnutls_set_write_compression (session, session->internals. compression_method); if (rc < 0) return rc; } else { /* RESUME_TRUE */ _gnutls_cpy_write_security_parameters (&session-> security_parameters, &session-> internals. resumed_security_parameters); } rc = _gnutls_set_write_keys (session); if (rc < 0) return rc; _gnutls_handshake_log ("HSK[%x]: Cipher Suite: %s\n", session, _gnutls_cipher_suite_get_name (&session-> security_parameters. current_cipher_suite)); if (_gnutls_compression_is_ok (session->security_parameters.write_compression_algorithm) != 0) { gnutls_assert (); return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM; } if (_gnutls_mac_is_ok (session->security_parameters.write_mac_algorithm) != 0) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } /* Free all the previous keys/ sessions etc. */ if (session->connection_state.write_mac_secret.data != NULL) _gnutls_free_datum (&session->connection_state.write_mac_secret); if (session->connection_state.write_cipher_state != NULL) _gnutls_cipher_deinit (session->connection_state.write_cipher_state); if (session->connection_state.write_compression_state != NULL) _gnutls_comp_deinit (session->connection_state. write_compression_state, 0); mac_size = _gnutls_hash_get_algo_len (session->security_parameters. write_mac_algorithm); _gnutls_handshake_log ("HSK[%x]: Initializing internal [write] cipher sessions\n", session); switch (session->security_parameters.entity) { case GNUTLS_SERVER: /* initialize cipher session */ session->connection_state.write_cipher_state = _gnutls_cipher_init (session->security_parameters. write_bulk_cipher_algorithm, &session->cipher_specs. server_write_key, &session->cipher_specs.server_write_IV); if (session->connection_state.write_cipher_state == GNUTLS_CIPHER_FAILED && session->security_parameters. write_bulk_cipher_algorithm != GNUTLS_CIPHER_NULL) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } /* copy mac secrets from cipherspecs, to connection * session. */ if (mac_size > 0) { if (_gnutls_sset_datum (&session->connection_state. write_mac_secret, session->cipher_specs. server_write_mac_secret.data, session->cipher_specs. server_write_mac_secret.size) < 0) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } } break; case GNUTLS_CLIENT: session->connection_state.write_cipher_state = _gnutls_cipher_init (session->security_parameters. write_bulk_cipher_algorithm, &session->cipher_specs. client_write_key, &session->cipher_specs.client_write_IV); if (session->connection_state.write_cipher_state == GNUTLS_CIPHER_FAILED && session->security_parameters. write_bulk_cipher_algorithm != GNUTLS_CIPHER_NULL) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } /* copy mac secret to connection session */ if (mac_size > 0) { if (_gnutls_sset_datum (&session->connection_state. write_mac_secret, session->cipher_specs. client_write_mac_secret.data, session->cipher_specs. client_write_mac_secret.size) < 0) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } } break; default: gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } session->connection_state.write_compression_state = _gnutls_comp_init (session->security_parameters. write_compression_algorithm, 0); if (session->connection_state.write_compression_state == GNUTLS_COMP_FAILED) { gnutls_assert (); return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM; } return 0; }
static int encrypt_ticket(gnutls_session_t session, session_ticket_ext_st * priv, struct ticket_st *ticket) { cipher_hd_st cipher_hd; gnutls_datum_t key, IV; gnutls_datum_t state = {NULL,0}, encrypted_state = {NULL,0}; uint8_t iv[IV_SIZE]; gnutls_datum_t mac_secret; uint32_t t; int ret; /* Pack security parameters. */ ret = _gnutls_session_pack(session, &state); if (ret < 0) { gnutls_assert(); return ret; } encrypted_state.size = ((state.size + BLOCK_SIZE - 1) / BLOCK_SIZE) * BLOCK_SIZE; encrypted_state.data = gnutls_calloc(1, encrypted_state.size); if (!encrypted_state.data) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } memcpy(encrypted_state.data, state.data, state.size); /* Encrypt state */ key.data = (void *) &priv->key[KEY_POS]; key.size = CIPHER_KEY_SIZE; IV.data = iv; IV.size = IV_SIZE; t = gnutls_time(0); memcpy(iv, &t, 4); ret = gnutls_rnd(GNUTLS_RND_NONCE, iv+4, IV_SIZE-4); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_cipher_init(&cipher_hd, cipher_to_entry(CIPHER), &key, &IV, 1); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_cipher_encrypt(&cipher_hd, encrypted_state.data, encrypted_state.size); if (ret < 0) { gnutls_assert(); goto cleanup2; } /* Fill the ticket structure to compute MAC. */ memcpy(ticket->key_name, &priv->key[NAME_POS], KEY_NAME_SIZE); memcpy(ticket->IV, IV.data, IV.size); ticket->encrypted_state_len = encrypted_state.size; ticket->encrypted_state = encrypted_state.data; mac_secret.data = &priv->key[MAC_SECRET_POS]; mac_secret.size = MAC_SECRET_SIZE; ret = digest_ticket(&mac_secret, ticket, ticket->mac); if (ret < 0) { gnutls_assert(); goto cleanup2; } encrypted_state.data = NULL; ret = 0; cleanup2: _gnutls_cipher_deinit(&cipher_hd); cleanup: _gnutls_free_datum(&state); _gnutls_free_datum(&encrypted_state); return ret; }
static int decrypt_ticket(gnutls_session_t session, session_ticket_ext_st * priv, struct ticket_st *ticket) { cipher_hd_st cipher_hd; gnutls_datum_t key, IV, state, mac_secret; uint8_t cmac[MAC_SIZE]; time_t timestamp = gnutls_time(0); int ret; /* Check the integrity of ticket */ mac_secret.data = (void *) &priv->key[MAC_SECRET_POS]; mac_secret.size = MAC_SECRET_SIZE; ret = digest_ticket(&mac_secret, ticket, cmac); if (ret < 0) return gnutls_assert_val(ret); if (memcmp(ticket->mac, cmac, MAC_SIZE)) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); if (ticket->encrypted_state_len % BLOCK_SIZE != 0) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); /* Decrypt encrypted_state */ key.data = (void *) &priv->key[KEY_POS]; key.size = CIPHER_KEY_SIZE; IV.data = ticket->IV; IV.size = IV_SIZE; ret = _gnutls_cipher_init(&cipher_hd, cipher_to_entry(CIPHER), &key, &IV, 0); if (ret < 0) { gnutls_assert(); return ret; } ret = _gnutls_cipher_decrypt(&cipher_hd, ticket->encrypted_state, ticket->encrypted_state_len); if (ret < 0) { gnutls_assert(); goto cleanup; } /* Unpack security parameters. */ state.data = ticket->encrypted_state; state.size = ticket->encrypted_state_len; ret = _gnutls_session_unpack(session, &state); if (ret < 0) { gnutls_assert(); goto cleanup; } if (timestamp - session->internals.resumed_security_parameters.timestamp > session->internals.expire_time || session->internals.resumed_security_parameters.timestamp > timestamp) { gnutls_assert(); ret = GNUTLS_E_EXPIRED; goto cleanup; } ret = _gnutls_check_resumed_params(session); if (ret < 0) { gnutls_assert(); goto cleanup; } session->internals.resumed = RESUME_TRUE; ret = 0; cleanup: _gnutls_cipher_deinit(&cipher_hd); return ret; }