static int gen_psk_client_kx (gnutls_session_t session, opaque ** data) { int ret; opaque *tmp_data = NULL; int data_size, tmp_data_size; gnutls_psk_client_credentials_t cred; cred = (gnutls_psk_client_credentials_t) _gnutls_get_cred (session->key, GNUTLS_CRD_PSK, NULL); if (cred == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } if (cred->username.data == NULL || cred->key.data == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } /* The PSK key is set in there */ ret = _gnutls_gen_dh_common_client_kx (session, &tmp_data); if (ret < 0) { gnutls_assert (); return ret; } tmp_data_size = ret; data_size = tmp_data_size + cred->username.size + 2; (*data) = gnutls_malloc (data_size); if ((*data) == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto error; } _gnutls_write_datum16 (*data, cred->username); memcpy (&(*data)[cred->username.size + 2], tmp_data, tmp_data_size); ret = data_size; error: gnutls_free (tmp_data); return ret; }
/* Set the PSK premaster secret. */ int _gnutls_set_psk_session_key (gnutls_session_t session, gnutls_datum_t * ppsk /* key */, gnutls_datum_t * dh_secret) { gnutls_datum_t pwd_psk = { NULL, 0 }; size_t dh_secret_size; int ret; if (dh_secret == NULL) dh_secret_size = ppsk->size; else dh_secret_size = dh_secret->size; /* set the session key */ session->key->key.size = 4 + dh_secret_size + ppsk->size; session->key->key.data = gnutls_malloc (session->key->key.size); if (session->key->key.data == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto error; } /* format of the premaster secret: * (uint16_t) psk_size * psk_size bytes of (0)s * (uint16_t) psk_size * the psk */ _gnutls_write_uint16 (dh_secret_size, session->key->key.data); if (dh_secret == NULL) memset (&session->key->key.data[2], 0, dh_secret_size); else memcpy (&session->key->key.data[2], dh_secret->data, dh_secret->size); _gnutls_write_datum16 (&session->key->key.data[dh_secret_size + 2], *ppsk); ret = 0; error: _gnutls_free_datum (&pwd_psk); return ret; }
/* Generates the PSK server key exchange * * struct { * select (KeyExchangeAlgorithm) { * // other cases for rsa, diffie_hellman, etc. * case psk: // NEW * opaque psk_identity_hint<0..2^16-1>; * }; * } ServerKeyExchange; * */ int _gnutls_gen_psk_server_kx (gnutls_session_t session, opaque ** data) { gnutls_psk_server_credentials_t cred; gnutls_datum_t hint; cred = (gnutls_psk_server_credentials_t) _gnutls_get_cred (session->key, GNUTLS_CRD_PSK, NULL); if (cred == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } /* Abort sending this message if there is no PSK identity hint. */ if (cred->hint == NULL) { gnutls_assert (); return GNUTLS_E_INT_RET_0; } hint.data = cred->hint; hint.size = strlen (cred->hint); (*data) = gnutls_malloc (2 + hint.size); if ((*data) == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } _gnutls_write_datum16 (*data, hint); return hint.size + 2; }
static int gen_dhe_server_kx (gnutls_session_t session, opaque ** data) { bigint_t g, p; const bigint_t *mpis; int ret = 0, data_size; gnutls_cert *apr_cert_list; gnutls_privkey_t apr_pkey; int apr_cert_list_length; gnutls_datum_t signature = { NULL, 0 }, ddata; gnutls_certificate_credentials_t cred; gnutls_dh_params_t dh_params; gnutls_sign_algorithm_t sign_algo; gnutls_protocol_t ver = gnutls_protocol_get_version (session); cred = (gnutls_certificate_credentials_t) _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL); if (cred == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } /* find the appropriate certificate */ if ((ret = _gnutls_get_selected_cert (session, &apr_cert_list, &apr_cert_list_length, &apr_pkey)) < 0) { gnutls_assert (); return ret; } dh_params = _gnutls_get_dh_params (cred->dh_params, cred->params_func, session); mpis = _gnutls_dh_params_to_mpi (dh_params); if (mpis == NULL) { gnutls_assert (); return GNUTLS_E_NO_TEMPORARY_DH_PARAMS; } p = mpis[0]; g = mpis[1]; if ((ret = _gnutls_auth_info_set (session, GNUTLS_CRD_CERTIFICATE, sizeof (cert_auth_info_st), 0)) < 0) { gnutls_assert (); return ret; } _gnutls_dh_set_group (session, g, p); ret = _gnutls_dh_common_print_server_kx (session, g, p, data, 0); if (ret < 0) { gnutls_assert (); return ret; } data_size = ret; /* Generate the signature. */ ddata.data = *data; ddata.size = data_size; if (apr_cert_list_length > 0) { if ((ret = _gnutls_handshake_sign_data (session, &apr_cert_list[0], apr_pkey, &ddata, &signature, &sign_algo)) < 0) { gnutls_assert (); goto cleanup; } } else { gnutls_assert (); ret = data_size; /* do not put a signature - ILLEGAL! */ goto cleanup; } *data = gnutls_realloc_fast (*data, data_size + signature.size + 4); if (*data == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } if (_gnutls_version_has_selectable_sighash (ver)) { const sign_algorithm_st *aid; if (sign_algo == GNUTLS_SIGN_UNKNOWN) { ret = GNUTLS_E_UNKNOWN_ALGORITHM; goto cleanup; } aid = _gnutls_sign_to_tls_aid (sign_algo); if (aid == NULL) { gnutls_assert(); ret = GNUTLS_E_UNKNOWN_ALGORITHM; goto cleanup; } (*data)[data_size++] = aid->hash_algorithm; (*data)[data_size++] = aid->sign_algorithm; } _gnutls_write_datum16 (&(*data)[data_size], signature); data_size += signature.size + 2; _gnutls_free_datum (&signature); return data_size; cleanup: _gnutls_free_datum (&signature); gnutls_free(*data); return ret; }
/* Send the first key exchange message ( g, n, s) and append the verifier algorithm number * Data is allocated by the caller, and should have data_size size. */ int _gnutls_gen_srp_server_kx (gnutls_session_t session, opaque ** data) { int ret; uint8_t *data_n, *data_s; uint8_t *data_g; char *username; SRP_PWD_ENTRY *pwd_entry; srp_server_auth_info_t info; ssize_t data_size; size_t n_b, tmp_size; char buf[64]; uint8_t *data_b; if ((ret = _gnutls_auth_info_set (session, GNUTLS_CRD_SRP, sizeof (srp_server_auth_info_st), 1)) < 0) { gnutls_assert (); return ret; } info = _gnutls_get_auth_info (session); username = info->username; _gnutls_str_cpy (username, MAX_SRP_USERNAME, session->security_parameters.extensions.srp_username); ret = _gnutls_srp_pwd_read_entry (session, username, &pwd_entry); if (ret < 0) { gnutls_assert (); return ret; } /* copy from pwd_entry to local variables (actually in session) */ tmp_size = pwd_entry->g.size; if (_gnutls_mpi_scan_nz (&G, pwd_entry->g.data, &tmp_size) < 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } tmp_size = pwd_entry->n.size; if (_gnutls_mpi_scan_nz (&N, pwd_entry->n.data, &tmp_size) < 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } tmp_size = pwd_entry->v.size; if (_gnutls_mpi_scan_nz (&V, pwd_entry->v.data, &tmp_size) < 0) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } /* Calculate: B = (k*v + g^b) % N */ B = _gnutls_calc_srp_B (&_b, G, N, V); if (B == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } if (_gnutls_mpi_print (NULL, &n_b, B) != 0) { gnutls_assert (); return GNUTLS_E_MPI_PRINT_FAILED; } /* Allocate size to hold the N, g, s, B */ data_size = (pwd_entry->n.size + 2 + pwd_entry->g.size + 2 + pwd_entry->salt.size + 1) + (n_b + 2); (*data) = gnutls_malloc (data_size); if ((*data) == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } /* copy N (mod n) */ data_n = *data; _gnutls_write_datum16 (data_n, pwd_entry->n); /* copy G (generator) to data */ data_g = &data_n[2 + pwd_entry->n.size]; _gnutls_write_datum16 (data_g, pwd_entry->g); /* copy the salt */ data_s = &data_g[2 + pwd_entry->g.size]; _gnutls_write_datum8 (data_s, pwd_entry->salt); /* Copy the B value */ data_b = &data_s[1 + pwd_entry->salt.size]; if (_gnutls_mpi_print (&data_b[2], &n_b, B) != 0) { gnutls_assert(); return GNUTLS_E_MPI_PRINT_FAILED; } _gnutls_write_uint16 (n_b, data_b); _gnutls_hard_log ("INT: SRP B[%d]: %s\n", n_b, _gnutls_bin2hex (&data_b[2], n_b, buf, sizeof (buf))); _gnutls_srp_entry_free (pwd_entry); return data_size; }
static int gen_srp_cert_server_kx (gnutls_session_t session, opaque ** data) { ssize_t ret, data_size; gnutls_datum_t signature, ddata; gnutls_certificate_credentials_t cred; gnutls_cert *apr_cert_list; gnutls_privkey_t apr_pkey; int apr_cert_list_length; gnutls_sign_algorithm_t sign_algo; ret = _gnutls_gen_srp_server_kx (session, data); if (ret < 0) return ret; data_size = ret; ddata.data = *data; ddata.size = data_size; cred = (gnutls_certificate_credentials_t) _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL); if (cred == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } /* find the appropriate certificate */ if ((ret = _gnutls_get_selected_cert (session, &apr_cert_list, &apr_cert_list_length, &apr_pkey)) < 0) { gnutls_assert (); return ret; } if ((ret = _gnutls_handshake_sign_data (session, &apr_cert_list[0], apr_pkey, &ddata, &signature, &sign_algo)) < 0) { gnutls_assert (); gnutls_free (*data); return ret; } *data = gnutls_realloc_fast (*data, data_size + signature.size + 2); if (*data == NULL) { _gnutls_free_datum (&signature); gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } _gnutls_write_datum16 (&(*data)[data_size], signature); data_size += signature.size + 2; _gnutls_free_datum (&signature); return data_size; }
static int gen_rsa_export_server_kx (gnutls_session_t session, opaque ** data) { gnutls_rsa_params_t rsa_params; const bigint_t *rsa_mpis; size_t n_e, n_m; uint8_t *data_e, *data_m; int ret = 0, data_size; gnutls_cert *apr_cert_list; gnutls_privkey *apr_pkey; int apr_cert_list_length; gnutls_datum_t signature, ddata; cert_auth_info_t info; gnutls_certificate_credentials_t cred; cred = (gnutls_certificate_credentials_t) _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL); if (cred == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } /* find the appropriate certificate */ if ((ret = _gnutls_get_selected_cert (session, &apr_cert_list, &apr_cert_list_length, &apr_pkey)) < 0) { gnutls_assert (); return ret; } /* abort sending this message if we have a certificate * of 512 bits or less. */ if (apr_pkey && _gnutls_mpi_get_nbits (apr_pkey->params[0]) <= 512) { gnutls_assert (); return GNUTLS_E_INT_RET_0; } rsa_params = _gnutls_certificate_get_rsa_params (cred->rsa_params, cred->params_func, session); rsa_mpis = _gnutls_rsa_params_to_mpi (rsa_params); if (rsa_mpis == NULL) { gnutls_assert (); return GNUTLS_E_NO_TEMPORARY_RSA_PARAMS; } if ((ret = _gnutls_auth_info_set (session, GNUTLS_CRD_CERTIFICATE, sizeof (cert_auth_info_st), 0)) < 0) { gnutls_assert (); return ret; } info = _gnutls_get_auth_info (session); _gnutls_rsa_export_set_pubkey (session, rsa_mpis[1], rsa_mpis[0]); _gnutls_mpi_print (rsa_mpis[0], NULL, &n_m); _gnutls_mpi_print (rsa_mpis[1], NULL, &n_e); (*data) = gnutls_malloc (n_e + n_m + 4); if (*data == NULL) { return GNUTLS_E_MEMORY_ERROR; } data_m = &(*data)[0]; _gnutls_mpi_print (rsa_mpis[0], &data_m[2], &n_m); _gnutls_write_uint16 (n_m, data_m); data_e = &data_m[2 + n_m]; _gnutls_mpi_print (rsa_mpis[1], &data_e[2], &n_e); _gnutls_write_uint16 (n_e, data_e); data_size = n_m + n_e + 4; /* Generate the signature. */ ddata.data = *data; ddata.size = data_size; if (apr_cert_list_length > 0) { if ((ret = _gnutls_tls_sign_params (session, &apr_cert_list[0], apr_pkey, &ddata, &signature)) < 0) { gnutls_assert (); gnutls_free (*data); *data = NULL; return ret; } } else { gnutls_assert (); return data_size; /* do not put a signature - ILLEGAL! */ } *data = gnutls_realloc_fast (*data, data_size + signature.size + 2); if (*data == NULL) { _gnutls_free_datum (&signature); gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } _gnutls_write_datum16 (&((*data)[data_size]), signature); data_size += signature.size + 2; _gnutls_free_datum (&signature); return data_size; }
/* return RSA(random) using the peers public key */ int _gnutls_gen_rsa_client_kx (gnutls_session_t session, opaque ** data) { cert_auth_info_t auth = session->key->auth_info; gnutls_datum_t sdata; /* data to send */ bigint_t params[MAX_PUBLIC_PARAMS_SIZE]; int params_len = MAX_PUBLIC_PARAMS_SIZE; int ret, i; gnutls_protocol_t ver; if (auth == NULL) { /* this shouldn't have happened. The proc_certificate * function should have detected that. */ gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } session->key->key.size = GNUTLS_MASTER_SIZE; session->key->key.data = gnutls_secure_malloc (session->key->key.size); if (session->key->key.data == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } ret = _gnutls_rnd (GNUTLS_RND_RANDOM, session->key->key.data, session->key->key.size); if (ret < 0) { gnutls_assert (); return ret; } ver = _gnutls_get_adv_version (session); if (session->internals.rsa_pms_version[0] == 0) { session->key->key.data[0] = _gnutls_version_get_major (ver); session->key->key.data[1] = _gnutls_version_get_minor (ver); } else { /* use the version provided */ session->key->key.data[0] = session->internals.rsa_pms_version[0]; session->key->key.data[1] = session->internals.rsa_pms_version[1]; } /* move RSA parameters to key (session). */ if ((ret = _gnutls_get_public_rsa_params (session, params, ¶ms_len)) < 0) { gnutls_assert (); return ret; } if ((ret = _gnutls_pkcs1_rsa_encrypt (&sdata, &session->key->key, params, params_len, 2)) < 0) { gnutls_assert (); return ret; } for (i = 0; i < params_len; i++) _gnutls_mpi_release (¶ms[i]); if (gnutls_protocol_get_version (session) == GNUTLS_SSL3) { /* SSL 3.0 */ *data = sdata.data; return sdata.size; } else { /* TLS 1 */ *data = gnutls_malloc (sdata.size + 2); if (*data == NULL) { _gnutls_free_datum (&sdata); return GNUTLS_E_MEMORY_ERROR; } _gnutls_write_datum16 (*data, sdata); ret = sdata.size + 2; _gnutls_free_datum (&sdata); return ret; } }
/* Set the PSK premaster secret. */ int _gnutls_set_psk_session_key (gnutls_session_t session, gnutls_datum_t * dh_secret) { gnutls_datum_t pwd_psk = { NULL, 0 }; gnutls_datum_t *ppsk; size_t dh_secret_size; int ret; if (session->security_parameters.entity == GNUTLS_CLIENT) { gnutls_psk_client_credentials_t cred; cred = (gnutls_psk_client_credentials_t) _gnutls_get_cred (session->key, GNUTLS_CRD_PSK, NULL); if (cred == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } ppsk = &cred->key; } else { /* SERVER side */ psk_auth_info_t info; info = _gnutls_get_auth_info (session); /* find the key of this username */ ret = _gnutls_psk_pwd_find_entry (session, info->username, &pwd_psk); if (ret < 0) { gnutls_assert (); return ret; } ppsk = &pwd_psk; } if (dh_secret == NULL) dh_secret_size = ppsk->size; else dh_secret_size = dh_secret->size; /* set the session key */ session->key->key.size = 4 + dh_secret_size + ppsk->size; session->key->key.data = gnutls_malloc (session->key->key.size); if (session->key->key.data == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto error; } /* format of the premaster secret: * (uint16_t) psk_size * psk_size bytes of zeros * (uint16_t) psk_size * the psk */ _gnutls_write_uint16 (dh_secret_size, session->key->key.data); if (dh_secret == NULL) memset (&session->key->key.data[2], 0, dh_secret_size); else memcpy (&session->key->key.data[2], dh_secret->data, dh_secret->size); _gnutls_write_datum16 (&session->key->key.data[dh_secret_size + 2], *ppsk); ret = 0; error: _gnutls_free_datum (&pwd_psk); return ret; }
/* Generates the PSK client key exchange * * * struct { * select (KeyExchangeAlgorithm) { * opaque psk_identity<0..2^16-1>; * } exchange_keys; * } ClientKeyExchange; * */ int _gnutls_gen_psk_client_kx (gnutls_session_t session, opaque ** data) { int ret; gnutls_psk_client_credentials_t cred; cred = (gnutls_psk_client_credentials_t) _gnutls_get_cred (session->key, GNUTLS_CRD_PSK, NULL); if (cred == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } if (cred->username.data == NULL && cred->key.data == NULL && cred->get_function != NULL) { char *username; gnutls_datum_t key; ret = cred->get_function (session, &username, &key); if (ret) { gnutls_assert (); return ret; } ret = _gnutls_set_datum (&cred->username, username, strlen (username)); gnutls_free (username); if (ret < 0) { gnutls_assert (); _gnutls_free_datum (&key); return ret; } ret = _gnutls_set_datum (&cred->key, key.data, key.size); _gnutls_free_datum (&key); if (ret < 0) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } } else if (cred->username.data == NULL || cred->key.data == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } ret = _gnutls_set_psk_session_key (session, NULL); if (ret < 0) { gnutls_assert (); return ret; } (*data) = gnutls_malloc (2 + cred->username.size); if ((*data) == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } _gnutls_write_datum16 (*data, cred->username); return (cred->username.size + 2); }