/* Randomizes the given password entry. It actually sets the verifier * and the salt. Returns 0 on success. */ static int _randomize_pwd_entry (SRP_PWD_ENTRY * entry) { unsigned char rnd; int ret; if (entry->g.size == 0 || entry->n.size == 0) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } ret = _gnutls_rnd (GNUTLS_RND_NONCE, &rnd, 1); if (ret < 0) { gnutls_assert (); return ret; } entry->salt.size = (rnd % 10) + 9; entry->v.data = gnutls_malloc (20); entry->v.size = 20; if (entry->v.data == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } ret = _gnutls_rnd (GNUTLS_RND_RANDOM, entry->v.data, 20); if (ret < 0) { gnutls_assert (); return ret; } entry->salt.data = gnutls_malloc (entry->salt.size); if (entry->salt.data == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } ret = _gnutls_rnd (GNUTLS_RND_NONCE, entry->salt.data, entry->salt.size); if (ret < 0) { gnutls_assert (); return ret; } return 0; }
/** * gnutls_srp_allocate_server_credentials: * @sc: is a pointer to a #gnutls_srp_server_credentials_t type. * * Allocate a gnutls_srp_server_credentials_t structure. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an * error code. **/ int gnutls_srp_allocate_server_credentials(gnutls_srp_server_credentials_t * sc) { int ret; *sc = gnutls_calloc(1, sizeof(srp_server_cred_st)); if (*sc == NULL) return GNUTLS_E_MEMORY_ERROR; (*sc)->fake_salt_seed.size = DEFAULT_FAKE_SALT_SEED_SIZE; (*sc)->fake_salt_seed.data = gnutls_malloc( DEFAULT_FAKE_SALT_SEED_SIZE); if ((*sc)->fake_salt_seed.data == NULL) { ret = GNUTLS_E_MEMORY_ERROR; gnutls_assert(); goto cleanup; } ret = _gnutls_rnd(GNUTLS_RND_RANDOM, (*sc)->fake_salt_seed.data, DEFAULT_FAKE_SALT_SEED_SIZE); if (ret < 0) { gnutls_assert(); goto cleanup; } (*sc)->fake_salt_length = DEFAULT_FAKE_SALT_SIZE; return 0; cleanup: _gnutls_free_datum(&(*sc)->fake_salt_seed); gnutls_free(*sc); return ret; }
void doit (void) { int rc; char buf1[32]; char buf2[32]; int failed = 0; gnutls_crypto_rnd_st rng = { rng_init, rng_rnd, rng_deinit }; rc = gnutls_crypto_rnd_register (0, &rng); gnutls_global_init (); memset (buf2, 1, sizeof (buf2)); _gnutls_rnd (GNUTLS_RND_RANDOM, buf1, sizeof (buf1)); if (memcmp (buf1, buf2, sizeof (buf1)) != 0) failed = 1; gnutls_global_deinit (); if (failed == 0) { success ("rng registered ok\n"); } else { fail ("rng register test failed: %d\n", rc); } }
FILE * _cdk_tmpfile (void) { /* Because the tmpfile() version of wine is not really useful, we implement our own version to avoid problems with 'make check'. */ static const char *letters = "abcdefghijklmnopqrstuvwxyz"; char buf[512], rnd[24]; FILE *fp; int fd, i; _gnutls_rnd (GNUTLS_RND_NONCE, rnd, DIM (rnd)); for (i = 0; i < DIM (rnd) - 1; i++) { char c = letters[(unsigned char) rnd[i] % 26]; rnd[i] = c; } rnd[DIM (rnd) - 1] = 0; if (!GetTempPath (464, buf)) return NULL; strcat (buf, "_cdk_"); strcat (buf, rnd); /* We need to make sure the file will be deleted when it is closed. */ fd = _open (buf, _O_CREAT | _O_EXCL | _O_TEMPORARY | _O_RDWR | _O_BINARY, _S_IREAD | _S_IWRITE); if (fd == -1) return NULL; fp = fdopen (fd, "w+b"); if (fp != NULL) return fp; _close (fd); return NULL; }
/* Randomizes the given password entry. It actually sets the verifier * to random data and sets the salt based on fake_salt_seed and * username. Returns 0 on success. */ static int _randomize_pwd_entry(SRP_PWD_ENTRY * entry, gnutls_srp_server_credentials_t sc, const char * username) { int ret; const mac_entry_st *me = mac_to_entry(SRP_FAKE_SALT_MAC); mac_hd_st ctx; size_t username_len = strlen(username); if (entry->g.size == 0 || entry->n.size == 0) { gnutls_assert(); return GNUTLS_E_INTERNAL_ERROR; } entry->v.data = gnutls_malloc(20); entry->v.size = 20; if (entry->v.data == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } ret = _gnutls_rnd(GNUTLS_RND_RANDOM, entry->v.data, 20); if (ret < 0) { gnutls_assert(); return ret; } /* Always allocate and work with the output size of the MAC, * even if they don't need salts that long, for convenience. * * In case an error occurs 'entry' (and the salt inside) * is deallocated by our caller: _gnutls_srp_pwd_read_entry(). */ entry->salt.data = gnutls_malloc(me->output_size); if (entry->salt.data == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } ret = _gnutls_mac_init(&ctx, me, sc->fake_salt_seed.data, sc->fake_salt_seed.size); if (ret < 0) { gnutls_assert(); return ret; } _gnutls_mac(&ctx, "salt", 4); _gnutls_mac(&ctx, username, username_len); _gnutls_mac_deinit(&ctx, entry->salt.data); /* Set length to the actual number of bytes they asked for. * This is always less than or equal to the output size of * the MAC, enforced by gnutls_srp_set_server_fake_salt_seed(). */ entry->salt.size = sc->fake_salt_length; return 0; }
inline static int calc_enc_length (gnutls_session_t session, int data_size, int hash_size, uint8_t * pad, int random_pad, cipher_type_t block_algo, uint16_t blocksize) { uint8_t rnd; int length, ret; *pad = 0; switch (block_algo) { case CIPHER_STREAM: length = data_size + hash_size; break; case CIPHER_BLOCK: ret = _gnutls_rnd (GNUTLS_RND_NONCE, &rnd, 1); if (ret < 0) { gnutls_assert (); return ret; } /* make rnd a multiple of blocksize */ if (session->security_parameters.version == GNUTLS_SSL3 || random_pad == 0) { rnd = 0; } else { rnd = (rnd / blocksize) * blocksize; /* added to avoid the case of pad calculated 0 * seen below for pad calculation. */ if (rnd > blocksize) rnd -= blocksize; } length = data_size + hash_size; *pad = (uint8_t) (blocksize - (length % blocksize)) + rnd; length += *pad; if (_gnutls_version_has_explicit_iv (session->security_parameters.version)) length += blocksize; /* for the IV */ break; default: gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } return length; }
static void rnd_func(void *_ctx, unsigned length, uint8_t * data) { if (_gnutls_rnd(GNUTLS_RND_RANDOM, data, length) < 0) { #ifdef ENABLE_FIPS140 _gnutls_switch_lib_state(LIB_STATE_ERROR); #else abort(); #endif } }
/* Randomizes the given password entry. It actually sets a random password. * Returns 0 on success. */ static int _randomize_psk(gnutls_datum_t * psk) { int ret; psk->data = gnutls_malloc(16); if (psk->data == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } psk->size = 16; ret = _gnutls_rnd(GNUTLS_RND_NONCE, (char *) psk->data, 16); if (ret < 0) { gnutls_assert(); return ret; } return 0; }
static int randomize_uuid(TSS_UUID * uuid) { uint8_t raw_uuid[16]; int ret; ret = _gnutls_rnd(GNUTLS_RND_NONCE, raw_uuid, sizeof(raw_uuid)); if (ret < 0) return gnutls_assert_val(ret); /* mark it as random uuid */ raw_uuid[6] &= 0x0f; raw_uuid[6] |= 0x40; raw_uuid[8] &= 0x0f; raw_uuid[8] |= 0x80; memcpy(&uuid->ulTimeLow, raw_uuid, 4); memcpy(&uuid->usTimeMid, &raw_uuid[4], 2); memcpy(&uuid->usTimeHigh, &raw_uuid[6], 2); uuid->bClockSeqHigh = raw_uuid[8]; uuid->bClockSeqLow = raw_uuid[9]; memcpy(&uuid->rgbNode, &raw_uuid[10], 6); return 0; }
/* return RSA(random) using the peers public key */ int _gnutls_gen_rsa_client_kx(gnutls_session_t session, gnutls_buffer_st * data) { cert_auth_info_t auth = session->key.auth_info; gnutls_datum_t sdata; /* data to send */ gnutls_pk_params_st params; int ret; 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_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; } if (session->internals.rsa_pms_version[0] == 0) { session->key.key.data[0] = _gnutls_get_adv_version_major(session); session->key.key.data[1] = _gnutls_get_adv_version_minor(session); } 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, ¶ms)) < 0) { gnutls_assert(); return ret; } ret = _gnutls_pk_encrypt(GNUTLS_PK_RSA, &sdata, &session->key.key, ¶ms); gnutls_pk_params_release(¶ms); if (ret < 0) return gnutls_assert_val(ret); if (get_num_version(session) == GNUTLS_SSL3) { /* SSL 3.0 */ _gnutls_buffer_replace_data(data, &sdata); return data->length; } else { /* TLS 1 */ ret = _gnutls_buffer_append_data_prefix(data, 16, sdata.data, sdata.size); _gnutls_free_datum(&sdata); return ret; } }
static int proc_rsa_client_kx(gnutls_session_t session, uint8_t * data, size_t _data_size) { gnutls_datum_t plaintext; gnutls_datum_t ciphertext; int ret, dsize; int use_rnd_key = 0; ssize_t data_size = _data_size; gnutls_datum_t rndkey = {NULL, 0}; if (get_num_version(session) == GNUTLS_SSL3) { /* SSL 3.0 */ ciphertext.data = data; ciphertext.size = data_size; } else { /* TLS 1.0 */ DECR_LEN(data_size, 2); ciphertext.data = &data[2]; dsize = _gnutls_read_uint16(data); if (dsize != data_size) { gnutls_assert(); return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; } ciphertext.size = dsize; } rndkey.size = GNUTLS_MASTER_SIZE; rndkey.data = gnutls_malloc(rndkey.size); if (rndkey.data == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } /* we do not need strong random numbers here. */ ret = _gnutls_rnd(GNUTLS_RND_NONCE, rndkey.data, rndkey.size); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_privkey_decrypt_data(session->internals.selected_key, 0, &ciphertext, &plaintext); if (ret < 0 || plaintext.size != GNUTLS_MASTER_SIZE) { /* In case decryption fails then don't inform * the peer. Just use a random key. (in order to avoid * attack against pkcs-1 formating). */ _gnutls_debug_log("auth_rsa: Possible PKCS #1 format attack\n"); use_rnd_key = 1; } else { /* If the secret was properly formatted, then * check the version number. */ if (_gnutls_get_adv_version_major(session) != plaintext.data[0] || (session->internals.priorities.allow_wrong_pms == 0 && _gnutls_get_adv_version_minor(session) != plaintext.data[1])) { /* No error is returned here, if the version number check * fails. We proceed normally. * That is to defend against the attack described in the paper * "Attacking RSA-based sessions in SSL/TLS" by Vlastimil Klima, * Ondej Pokorny and Tomas Rosa. */ _gnutls_debug_log("auth_rsa: Possible PKCS #1 version check format attack\n"); } } if (use_rnd_key != 0) { session->key.key.data = rndkey.data; session->key.key.size = rndkey.size; rndkey.data = NULL; } else { session->key.key.data = plaintext.data; session->key.key.size = plaintext.size; } /* This is here to avoid the version check attack * discussed above. */ session->key.key.data[0] = _gnutls_get_adv_version_major(session); session->key.key.data[1] = _gnutls_get_adv_version_minor(session); ret = 0; cleanup: gnutls_free(rndkey.data); return ret; }
int main (int argc, char **argv) { gaainfo info; int ret; struct passwd *pwd; unsigned char key[MAX_KEY_SIZE]; char hex_key[MAX_KEY_SIZE * 2 + 1]; gnutls_datum_t dkey; size_t hex_key_size = sizeof (hex_key); if ((ret = gnutls_global_init ()) < 0) { fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret)); exit (1); } umask (066); if (gaa (argc, argv, &info) != -1) { fprintf (stderr, "Error in the arguments.\n"); return -1; } if (info.passwd == NULL) info.passwd = KPASSWD; if (info.username == NULL) { #ifndef _WIN32 pwd = getpwuid (getuid ()); if (pwd == NULL) { fprintf (stderr, "No such user\n"); return -1; } info.username = pwd->pw_name; #else fprintf (stderr, "Please specify a user\n"); return -1; #endif } if (info.key_size > MAX_KEY_SIZE) { fprintf (stderr, "Key size is too long\n"); exit (1); } if (info.netconf_hint) { char *passwd; if (info.key_size != 0 && info.key_size != 20) { fprintf (stderr, "For netconf, key size must always be 20.\n"); exit (1); } passwd = getpass ("Enter password: "******"Please specify a password\n"); exit (1); } ret = gnutls_psk_netconf_derive_key (passwd, info.username, info.netconf_hint, &dkey); } else { if (info.key_size < 1) info.key_size = 16; printf ("Generating a random key for user '%s'\n", info.username); ret = _gnutls_rnd (GNUTLS_RND_RANDOM, (char *) key, info.key_size); if (ret < 0) { fprintf (stderr, "Not enough randomness\n"); exit (1); } dkey.data = key; dkey.size = info.key_size; } ret = gnutls_hex_encode (&dkey, hex_key, &hex_key_size); if (info.netconf_hint) gnutls_free (dkey.data); if (ret < 0) { fprintf (stderr, "HEX encoding error\n"); exit (1); } ret = write_key (info.username, hex_key, hex_key_size, info.passwd); if (ret == 0) printf ("Key stored to %s\n", info.passwd); return ret; }
/** * gnutls_rnd: * @level: a security level * @data: place to store random bytes * @len: The requested size * * This function will generate random data and store it to output * buffer. * * Returns: Zero or a negative error code on error. * * Since: 2.12.0 **/ int gnutls_rnd (gnutls_rnd_level_t level, void *data, size_t len) { return _gnutls_rnd(level, data, len); }
/** * gnutls_pkcs11_copy_secret_key: * @token_url: A PKCS #11 URL specifying a token * @key: The raw key * @label: A name to be used for the stored data * @key_usage: One of GNUTLS_KEY_* * @flags: One of GNUTLS_PKCS11_OBJ_FLAG_* * * This function will copy a raw secret (symmetric) key into a PKCS #11 * token specified by a URL. The key can be marked as sensitive or not. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 2.12.0 **/ int gnutls_pkcs11_copy_secret_key(const char *token_url, gnutls_datum_t * key, const char *label, unsigned int key_usage, unsigned int flags /* GNUTLS_PKCS11_OBJ_FLAG_* */ ) { int ret; struct p11_kit_uri *info = NULL; ck_rv_t rv; struct ck_attribute a[12]; ck_object_class_t class = CKO_SECRET_KEY; ck_object_handle_t obj; ck_key_type_t keytype = CKK_GENERIC_SECRET; ck_bool_t tval = 1; int a_val; uint8_t id[16]; struct pkcs11_session_info sinfo; PKCS11_CHECK_INIT; memset(&sinfo, 0, sizeof(sinfo)); ret = pkcs11_url_to_info(token_url, &info); if (ret < 0) { gnutls_assert(); return ret; } /* generate a unique ID */ ret = _gnutls_rnd(GNUTLS_RND_NONCE, id, sizeof(id)); if (ret < 0) { gnutls_assert(); return ret; } ret = pkcs11_open_session(&sinfo, NULL, info, SESSION_WRITE | pkcs11_obj_flags_to_int(flags)); p11_kit_uri_free(info); if (ret < 0) { gnutls_assert(); return ret; } /* FIXME: copy key usage flags */ a[0].type = CKA_CLASS; a[0].value = &class; a[0].value_len = sizeof(class); a[1].type = CKA_VALUE; a[1].value = key->data; a[1].value_len = key->size; a[2].type = CKA_TOKEN; a[2].value = &tval; a[2].value_len = sizeof(tval); a[3].type = CKA_PRIVATE; a[3].value = &tval; a[3].value_len = sizeof(tval); a[4].type = CKA_KEY_TYPE; a[4].value = &keytype; a[4].value_len = sizeof(keytype); a[5].type = CKA_ID; a[5].value = id; a[5].value_len = sizeof(id); a_val = 6; if (label) { a[a_val].type = CKA_LABEL; a[a_val].value = (void *) label; a[a_val].value_len = strlen(label); a_val++; } if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE) tval = 1; else tval = 0; a[a_val].type = CKA_SENSITIVE; a[a_val].value = &tval; a[a_val].value_len = sizeof(tval); a_val++; rv = pkcs11_create_object(sinfo.module, sinfo.pks, a, a_val, &obj); if (rv != CKR_OK) { gnutls_assert(); _gnutls_debug_log("p11: %s\n", pkcs11_strerror(rv)); ret = pkcs11_rv_to_err(rv); goto cleanup; } /* generated! */ ret = 0; cleanup: pkcs11_close_session(&sinfo); return ret; }
/* This is the actual encryption * Encrypts the given compressed datum, and puts the result to cipher_data, * which has cipher_size size. * return the actual encrypted data length. */ int _gnutls_compressed2ciphertext (gnutls_session_t session, opaque * cipher_data, int cipher_size, gnutls_datum_t compressed, content_type_t _type, int random_pad) { uint8_t MAC[MAX_HASH_SIZE]; uint16_t c_length; uint8_t pad; int length, ret; digest_hd_st td; uint8_t type = _type; uint8_t major, minor; int hash_size = _gnutls_hash_get_algo_len (session->security_parameters. write_mac_algorithm); gnutls_protocol_t ver; int blocksize = _gnutls_cipher_get_block_size (session->security_parameters. write_bulk_cipher_algorithm); cipher_type_t block_algo = _gnutls_cipher_is_block (session->security_parameters. write_bulk_cipher_algorithm); opaque *data_ptr; ver = gnutls_protocol_get_version (session); minor = _gnutls_version_get_minor (ver); major = _gnutls_version_get_major (ver); /* Initialize MAC */ ret = mac_init (&td, session->security_parameters.write_mac_algorithm, session->connection_state.write_mac_secret.data, session->connection_state.write_mac_secret.size, ver); if (ret < 0 && session->security_parameters.write_mac_algorithm != GNUTLS_MAC_NULL) { gnutls_assert (); return ret; } c_length = _gnutls_conv_uint16 (compressed.size); if (session->security_parameters.write_mac_algorithm != GNUTLS_MAC_NULL) { /* actually when the algorithm in not the NULL one */ _gnutls_hmac (&td, UINT64DATA (session->connection_state. write_sequence_number), 8); _gnutls_hmac (&td, &type, 1); if (ver >= GNUTLS_TLS1) { /* TLS 1.0 or higher */ _gnutls_hmac (&td, &major, 1); _gnutls_hmac (&td, &minor, 1); } _gnutls_hmac (&td, &c_length, 2); _gnutls_hmac (&td, compressed.data, compressed.size); mac_deinit (&td, MAC, ver); } /* Calculate the encrypted length (padding etc.) */ length = calc_enc_length (session, compressed.size, hash_size, &pad, random_pad, block_algo, blocksize); if (length < 0) { gnutls_assert (); return length; } /* copy the encrypted data to cipher_data. */ if (cipher_size < length) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } data_ptr = cipher_data; if (block_algo == CIPHER_BLOCK && session->security_parameters.version >= GNUTLS_TLS1_1) { /* copy the random IV. */ ret = _gnutls_rnd (GNUTLS_RND_NONCE, data_ptr, blocksize); if (ret < 0) { gnutls_assert (); return ret; } data_ptr += blocksize; } memcpy (data_ptr, compressed.data, compressed.size); data_ptr += compressed.size; if (hash_size > 0) { memcpy (data_ptr, MAC, hash_size); data_ptr += hash_size; } if (block_algo == CIPHER_BLOCK && pad > 0) { memset (data_ptr, pad - 1, pad); } /* Actual encryption (inplace). */ ret = _gnutls_cipher_encrypt (&session->connection_state.write_cipher_state, cipher_data, length); if (ret < 0) { gnutls_assert (); return ret; } return length; }
/* This is the actual encryption * Encrypts the given compressed datum, and puts the result to cipher_data, * which has cipher_size size. * return the actual encrypted data length. */ int _gnutls_compressed2ciphertext (gnutls_session_t session, opaque * cipher_data, int cipher_size, gnutls_datum_t compressed, content_type_t _type, int random_pad, record_parameters_st * params) { uint8_t MAC[MAX_HASH_SIZE]; uint16_t c_length; uint8_t pad; int length, ret; uint8_t type = _type; opaque preamble[PREAMBLE_SIZE]; int preamble_size; int hash_size = _gnutls_hash_get_algo_len (params->mac_algorithm); int blocksize = gnutls_cipher_get_block_size (params->cipher_algorithm); cipher_type_t block_algo = _gnutls_cipher_is_block (params->cipher_algorithm); opaque *data_ptr; int ver = gnutls_protocol_get_version (session); /* Initialize MAC */ c_length = _gnutls_conv_uint16 (compressed.size); if (params->mac_algorithm != GNUTLS_MAC_NULL) { /* actually when the algorithm in not the NULL one */ digest_hd_st td; ret = mac_init (&td, params->mac_algorithm, params->write.mac_secret.data, params->write.mac_secret.size, ver); if (ret < 0) { gnutls_assert (); return ret; } preamble_size = make_preamble (UINT64DATA (params->write.sequence_number), type, c_length, ver, preamble); mac_hash (&td, preamble, preamble_size, ver); mac_hash (&td, compressed.data, compressed.size, ver); mac_deinit (&td, MAC, ver); } /* Calculate the encrypted length (padding etc.) */ length = calc_enc_length (session, compressed.size, hash_size, &pad, random_pad, block_algo, blocksize); if (length < 0) { gnutls_assert (); return length; } /* copy the encrypted data to cipher_data. */ if (cipher_size < length) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } data_ptr = cipher_data; if (block_algo == CIPHER_BLOCK && _gnutls_version_has_explicit_iv (session->security_parameters.version)) { /* copy the random IV. */ ret = _gnutls_rnd (GNUTLS_RND_NONCE, data_ptr, blocksize); if (ret < 0) { gnutls_assert (); return ret; } data_ptr += blocksize; } memcpy (data_ptr, compressed.data, compressed.size); data_ptr += compressed.size; if (hash_size > 0) { memcpy (data_ptr, MAC, hash_size); data_ptr += hash_size; } if (block_algo == CIPHER_BLOCK && pad > 0) { memset (data_ptr, pad - 1, pad); } /* Actual encryption (inplace). */ ret = _gnutls_cipher_encrypt (¶ms->write.cipher_state, cipher_data, length); if (ret < 0) { gnutls_assert (); return ret; } return length; }
bigint_t _gnutls_mpi_randomize (bigint_t r, unsigned int bits, gnutls_rnd_level_t level) { size_t size = 1 + (bits / 8); int ret; int rem, i; bigint_t tmp; char tmpbuf[512]; opaque *buf; int buf_release = 0; if (size < sizeof (tmpbuf)) { buf = tmpbuf; } else { buf = gnutls_malloc (size); if (buf == NULL) { gnutls_assert (); goto cleanup; } buf_release = 1; } ret = _gnutls_rnd (level, buf, size); if (ret < 0) { gnutls_assert (); goto cleanup; } /* mask the bits that weren't requested */ rem = bits % 8; if (rem == 0) { buf[0] = 0; } else { for (i = 8; i >= rem; i--) buf[0] = clearbit (buf[0], i); } ret = _gnutls_mpi_scan (&tmp, buf, size); if (ret < 0) { gnutls_assert (); goto cleanup; } if (buf_release != 0) { gnutls_free (buf); buf = NULL; } if (r != NULL) { _gnutls_mpi_set (r, tmp); _gnutls_mpi_release (&tmp); return r; } return tmp; cleanup: if (buf_release != 0) gnutls_free (buf); return NULL; }
static int compressed_to_ciphertext_new(gnutls_session_t session, uint8_t * cipher_data, int cipher_size, gnutls_datum_t * compressed, size_t min_pad, content_type_t type, record_parameters_st * params) { uint16_t pad = min_pad; int length, length_to_encrypt, ret; uint8_t preamble[MAX_PREAMBLE_SIZE]; int preamble_size; int tag_size = _gnutls_auth_cipher_tag_len(¶ms->write.cipher_state); int blocksize = _gnutls_cipher_get_block_size(params->cipher); unsigned block_algo = _gnutls_cipher_is_block(params->cipher); uint8_t *data_ptr; const version_entry_st *ver = get_version(session); int explicit_iv = _gnutls_version_has_explicit_iv(ver); int auth_cipher = _gnutls_auth_cipher_is_aead(¶ms->write.cipher_state); uint8_t nonce[MAX_CIPHER_BLOCK_SIZE]; unsigned iv_size, final_cipher_size; if (unlikely(ver == NULL)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); iv_size = _gnutls_cipher_get_implicit_iv_size(params->cipher); _gnutls_hard_log("ENC[%p]: cipher: %s, MAC: %s, Epoch: %u\n", session, _gnutls_cipher_get_name(params->cipher), _gnutls_mac_get_name(params->mac), (unsigned int) params->epoch); /* Call _gnutls_rnd() once. Get data used for the IV */ ret = _gnutls_rnd(GNUTLS_RND_NONCE, nonce, blocksize); if (ret < 0) return gnutls_assert_val(ret); /* cipher_data points to the start of data to be encrypted */ data_ptr = cipher_data; length_to_encrypt = length = 0; if (explicit_iv) { if (block_algo == CIPHER_BLOCK) { /* copy the random IV. */ DECR_LEN(cipher_size, blocksize); memcpy(data_ptr, nonce, blocksize); _gnutls_auth_cipher_setiv(¶ms->write. cipher_state, data_ptr, blocksize); data_ptr += blocksize; cipher_data += blocksize; length += blocksize; } else if (auth_cipher) { /* Values in AEAD are pretty fixed in TLS 1.2 for 128-bit block */ if (params->write.IV.data == NULL || params->write.IV.size != AEAD_IMPLICIT_DATA_SIZE) return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR); /* Instead of generating a new nonce on every packet, we use the * write.sequence_number (It is a MAY on RFC 5288). */ memcpy(nonce, params->write.IV.data, params->write.IV.size); memcpy(&nonce[AEAD_IMPLICIT_DATA_SIZE], UINT64DATA(params->write.sequence_number), 8); _gnutls_auth_cipher_setiv(¶ms->write. cipher_state, nonce, AEAD_IMPLICIT_DATA_SIZE + AEAD_EXPLICIT_DATA_SIZE); /* copy the explicit part */ DECR_LEN(cipher_size, AEAD_EXPLICIT_DATA_SIZE); memcpy(data_ptr, &nonce[AEAD_IMPLICIT_DATA_SIZE], AEAD_EXPLICIT_DATA_SIZE); data_ptr += AEAD_EXPLICIT_DATA_SIZE; cipher_data += AEAD_EXPLICIT_DATA_SIZE; length += AEAD_EXPLICIT_DATA_SIZE; } else if (iv_size > 0) _gnutls_auth_cipher_setiv(¶ms->write. cipher_state, UINT64DATA(params->write. sequence_number), 8); } else { /* AEAD ciphers have an explicit IV. Shouldn't be used otherwise. */ if (auth_cipher) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); } DECR_LEN(cipher_size, 2); if (block_algo == CIPHER_BLOCK) { /* make pad a multiple of blocksize */ unsigned t = (2 + pad + compressed->size + tag_size) % blocksize; if (t > 0) { pad += blocksize - t; } } _gnutls_write_uint16(pad, data_ptr); data_ptr += 2; length_to_encrypt += 2; length += 2; final_cipher_size = cipher_size; if (pad > 0) { unsigned t; t = cipher_size - compressed->size; if (pad > t) { if (block_algo == CIPHER_BLOCK) { if (pad <= blocksize) return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST); pad -= blocksize * ((pad - t) / blocksize); } else pad = t; } DECR_LEN(cipher_size, pad); memset(data_ptr, 0, pad); data_ptr += pad; length_to_encrypt += pad; length += pad; } DECR_LEN(cipher_size, compressed->size); memcpy(data_ptr, compressed->data, compressed->size); data_ptr += compressed->size; length_to_encrypt += compressed->size; length += compressed->size; if (tag_size > 0) { DECR_LEN(cipher_size, tag_size); data_ptr += tag_size; /* In AEAD ciphers we don't encrypt the tag */ length += tag_size; } preamble_size = make_preamble(UINT64DATA (params->write.sequence_number), type, compressed->size + 2 + pad, ver, preamble); _gnutls_auth_cipher_set_mac_nonce(¶ms->write.cipher_state, UINT64DATA(params->write. sequence_number), 8); /* add the authenticated data */ ret = _gnutls_auth_cipher_add_auth(¶ms->write.cipher_state, preamble, preamble_size); if (ret < 0) return gnutls_assert_val(ret); /* Actual encryption (inplace). */ ret = _gnutls_auth_cipher_encrypt2_tag(¶ms->write.cipher_state, cipher_data, length_to_encrypt, cipher_data, final_cipher_size, 0); if (ret < 0) return gnutls_assert_val(ret); return length; }
int RAND_pseudo_bytes (unsigned char *buf, int num) { _gnutls_rnd (GNUTLS_RND_NONCE, buf, num); return 1; }
/** * gnutls_tpm_privkey_generate: * @pk: the public key algorithm * @bits: the security bits * @srk_password: a password to protect the exported key (optional) * @key_password: the password for the TPM (optional) * @format: the format of the private key * @pub_format: the format of the public key * @privkey: the generated key * @pubkey: the corresponding public key (may be null) * @flags: should be a list of GNUTLS_TPM_* flags * * This function will generate a private key in the TPM * chip. The private key will be generated within the chip * and will be exported in a wrapped with TPM's master key * form. Furthermore the wrapped key can be protected with * the provided @password. * * Note that bits in TPM is quantized value. If the input value * is not one of the allowed values, then it will be quantized to * one of 512, 1024, 2048, 4096, 8192 and 16384. * * Allowed flags are: * * %GNUTLS_TPM_KEY_SIGNING: Generate a signing key instead of a legacy, * %GNUTLS_TPM_REGISTER_KEY: Register the generate key in TPM. In that * case @privkey would contain a URL with the UUID. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.1.0 **/ int gnutls_tpm_privkey_generate(gnutls_pk_algorithm_t pk, unsigned int bits, const char *srk_password, const char *key_password, gnutls_tpmkey_fmt_t format, gnutls_x509_crt_fmt_t pub_format, gnutls_datum_t * privkey, gnutls_datum_t * pubkey, unsigned int flags) { TSS_FLAG tpm_flags = TSS_KEY_VOLATILE; TSS_HKEY key_ctx; TSS_RESULT tssret; int ret; void *tdata; UINT32 tint; gnutls_datum_t tmpkey = { NULL, 0 }; TSS_HPOLICY key_policy; gnutls_pubkey_t pub; struct tpm_ctx_st s; TSS_FLAG storage_type; TSS_HTPM htpm; uint8_t buf[32]; if (flags & GNUTLS_TPM_KEY_SIGNING) tpm_flags |= TSS_KEY_TYPE_SIGNING; else tpm_flags |= TSS_KEY_TYPE_LEGACY; if (flags & GNUTLS_TPM_KEY_USER) storage_type = TSS_PS_TYPE_USER; else storage_type = TSS_PS_TYPE_SYSTEM; if (bits <= 512) tpm_flags |= TSS_KEY_SIZE_512; else if (bits <= 1024) tpm_flags |= TSS_KEY_SIZE_1024; else if (bits <= 2048) tpm_flags |= TSS_KEY_SIZE_2048; else if (bits <= 4096) tpm_flags |= TSS_KEY_SIZE_4096; else if (bits <= 8192) tpm_flags |= TSS_KEY_SIZE_8192; else tpm_flags |= TSS_KEY_SIZE_16384; ret = tpm_open_session(&s, srk_password); if (ret < 0) return gnutls_assert_val(ret); /* put some randomness into TPM. * Let's not trust it completely. */ tssret = Tspi_Context_GetTpmObject(s.tpm_ctx, &htpm); if (tssret != 0) { gnutls_assert(); ret = tss_err(tssret); goto err_cc; } ret = _gnutls_rnd(GNUTLS_RND_RANDOM, buf, sizeof(buf)); if (ret < 0) { gnutls_assert(); goto err_cc; } tssret = Tspi_TPM_StirRandom(htpm, sizeof(buf), buf); if (tssret) { gnutls_assert(); } tssret = Tspi_Context_CreateObject(s.tpm_ctx, TSS_OBJECT_TYPE_RSAKEY, tpm_flags, &key_ctx); if (tssret != 0) { gnutls_assert(); ret = tss_err(tssret); goto err_cc; } tssret = Tspi_SetAttribUint32(key_ctx, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_SIGSCHEME, TSS_SS_RSASSAPKCS1V15_DER); if (tssret != 0) { gnutls_assert(); ret = tss_err(tssret); goto err_sa; } /* set the password of the actual key */ if (key_password) { tssret = Tspi_GetPolicyObject(key_ctx, TSS_POLICY_USAGE, &key_policy); if (tssret != 0) { gnutls_assert(); ret = tss_err(tssret); goto err_sa; } tssret = myTspi_Policy_SetSecret(key_policy, SAFE_LEN(key_password), (void *) key_password); if (tssret != 0) { gnutls_assert(); ret = tss_err(tssret); goto err_sa; } } tssret = Tspi_Key_CreateKey(key_ctx, s.srk, 0); if (tssret != 0) { gnutls_assert(); ret = tss_err(tssret); goto err_sa; } if (flags & GNUTLS_TPM_REGISTER_KEY) { TSS_UUID key_uuid; ret = randomize_uuid(&key_uuid); if (ret < 0) { gnutls_assert(); goto err_sa; } tssret = Tspi_Context_RegisterKey(s.tpm_ctx, key_ctx, storage_type, key_uuid, TSS_PS_TYPE_SYSTEM, srk_uuid); if (tssret != 0) { gnutls_assert(); ret = tss_err(tssret); goto err_sa; } ret = encode_tpmkey_url((char **) &privkey->data, &key_uuid, storage_type); if (ret < 0) { TSS_HKEY tkey; Tspi_Context_UnregisterKey(s.tpm_ctx, storage_type, key_uuid, &tkey); gnutls_assert(); goto err_sa; } privkey->size = strlen((char *) privkey->data); } else { /* get the key as blob */ tssret = Tspi_GetAttribData(key_ctx, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_BLOB, &tint, (void *) &tdata); if (tssret != 0) { gnutls_assert(); ret = tss_err(tssret); goto err_sa; } if (format == GNUTLS_TPMKEY_FMT_CTK_PEM) { ret = _gnutls_x509_encode_string (ASN1_ETYPE_OCTET_STRING, tdata, tint, &tmpkey); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_fbase64_encode("TSS KEY BLOB", tmpkey.data, tmpkey.size, privkey); if (ret < 0) { gnutls_assert(); goto cleanup; } } else { UINT32 tint2; tmpkey.size = tint + 32; /* spec says no more than 20 */ tmpkey.data = gnutls_malloc(tmpkey.size); if (tmpkey.data == NULL) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } tint2 = tmpkey.size; tssret = Tspi_EncodeDER_TssBlob(tint, tdata, TSS_BLOB_TYPE_PRIVATEKEY, &tint2, tmpkey.data); if (tssret != 0) { gnutls_assert(); ret = tss_err(tssret); goto cleanup; } tmpkey.size = tint2; privkey->data = tmpkey.data; privkey->size = tmpkey.size; tmpkey.data = NULL; } } /* read the public key */ if (pubkey != NULL) { size_t psize; ret = gnutls_pubkey_init(&pub); if (ret < 0) { gnutls_assert(); goto privkey_cleanup; } ret = read_pubkey(pub, key_ctx, &psize); if (ret < 0) { gnutls_assert(); goto privkey_cleanup; } psize += 512; pubkey->data = gnutls_malloc(psize); if (pubkey->data == NULL) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto pubkey_cleanup; } ret = gnutls_pubkey_export(pub, pub_format, pubkey->data, &psize); if (ret < 0) { gnutls_assert(); goto pubkey_cleanup; } pubkey->size = psize; gnutls_pubkey_deinit(pub); } ret = 0; goto cleanup; pubkey_cleanup: gnutls_pubkey_deinit(pub); privkey_cleanup: gnutls_free(privkey->data); privkey->data = NULL; cleanup: gnutls_free(tmpkey.data); tmpkey.data = NULL; err_sa: Tspi_Context_CloseObject(s.tpm_ctx, key_ctx); err_cc: tpm_close_session(&s); return ret; }
static void rnd_func (void *_ctx, unsigned length, uint8_t * data) { _gnutls_rnd (GNUTLS_RND_RANDOM, data, length); }
/* This is the actual encryption * Encrypts the given compressed datum, and puts the result to cipher_data, * which has cipher_size size. * return the actual encrypted data length. */ static int compressed_to_ciphertext(gnutls_session_t session, uint8_t * cipher_data, int cipher_size, gnutls_datum_t * compressed, size_t min_pad, content_type_t type, record_parameters_st * params) { uint8_t pad; int length, ret; uint8_t preamble[MAX_PREAMBLE_SIZE]; int preamble_size; int tag_size = _gnutls_auth_cipher_tag_len(¶ms->write.cipher_state); int blocksize = _gnutls_cipher_get_block_size(params->cipher); unsigned algo_type = _gnutls_cipher_type(params->cipher); uint8_t *data_ptr, *full_cipher_ptr; const version_entry_st *ver = get_version(session); int explicit_iv = _gnutls_version_has_explicit_iv(ver); int auth_cipher = _gnutls_auth_cipher_is_aead(¶ms->write.cipher_state); uint8_t nonce[MAX_CIPHER_BLOCK_SIZE]; unsigned imp_iv_size = 0, exp_iv_size = 0; bool etm = 0; if (unlikely(ver == NULL)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); if (algo_type == CIPHER_BLOCK && params->etm != 0) etm = 1; _gnutls_hard_log("ENC[%p]: cipher: %s, MAC: %s, Epoch: %u\n", session, _gnutls_cipher_get_name(params->cipher), _gnutls_mac_get_name(params->mac), (unsigned int) params->epoch); /* Calculate the encrypted length (padding etc.) */ if (algo_type == CIPHER_BLOCK) { /* Call _gnutls_rnd() once. Get data used for the IV */ ret = _gnutls_rnd(GNUTLS_RND_NONCE, nonce, blocksize); if (ret < 0) return gnutls_assert_val(ret); pad = min_pad; length = calc_enc_length_block(session, ver, compressed->size, tag_size, &pad, auth_cipher, blocksize, etm); } else { /* AEAD + STREAM */ imp_iv_size = _gnutls_cipher_get_implicit_iv_size(params->cipher); exp_iv_size = _gnutls_cipher_get_explicit_iv_size(params->cipher); pad = 0; length = calc_enc_length_stream(session, compressed->size, tag_size, auth_cipher, exp_iv_size); } if (length < 0) return gnutls_assert_val(length); /* copy the encrypted data to cipher_data. */ if (cipher_size < length) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); data_ptr = cipher_data; full_cipher_ptr = data_ptr; if (algo_type == CIPHER_BLOCK || algo_type == CIPHER_STREAM) { if (algo_type == CIPHER_BLOCK && explicit_iv != 0) { /* copy the random IV. */ memcpy(data_ptr, nonce, blocksize); _gnutls_auth_cipher_setiv(¶ms->write. cipher_state, data_ptr, blocksize); data_ptr += blocksize; cipher_data += blocksize; } } else { /* AEAD */ /* Values in AEAD are pretty fixed in TLS 1.2 for 128-bit block */ if (params->write.IV.data == NULL || params->write.IV.size != imp_iv_size) return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR); /* Instead of generating a new nonce on every packet, we use the * write.sequence_number (It is a MAY on RFC 5288), and safer * as it will never reuse a value. */ memcpy(nonce, params->write.IV.data, params->write.IV.size); memcpy(&nonce[imp_iv_size], UINT64DATA(params->write.sequence_number), 8); /* copy the explicit part */ memcpy(data_ptr, &nonce[imp_iv_size], exp_iv_size); data_ptr += exp_iv_size; cipher_data += exp_iv_size; } if (etm) ret = length-tag_size; else ret = compressed->size; preamble_size = make_preamble(UINT64DATA(params->write.sequence_number), type, ret, ver, preamble); if (algo_type == CIPHER_BLOCK || algo_type == CIPHER_STREAM) { /* add the authenticated data */ ret = _gnutls_auth_cipher_add_auth(¶ms->write.cipher_state, preamble, preamble_size); if (ret < 0) return gnutls_assert_val(ret); if (etm && explicit_iv) { /* In EtM we need to hash the IV as well */ ret = _gnutls_auth_cipher_add_auth(¶ms->write.cipher_state, full_cipher_ptr, blocksize); if (ret < 0) return gnutls_assert_val(ret); } /* Actual encryption. */ ret = _gnutls_auth_cipher_encrypt2_tag(¶ms->write.cipher_state, compressed->data, compressed->size, cipher_data, cipher_size, pad); if (ret < 0) return gnutls_assert_val(ret); } else { /* AEAD */ ret = _gnutls_aead_cipher_encrypt(¶ms->write.cipher_state.cipher, nonce, imp_iv_size + exp_iv_size, preamble, preamble_size, tag_size, compressed->data, compressed->size, cipher_data, cipher_size); if (ret < 0) return gnutls_assert_val(ret); } return length; }
/* Do PKCS-1 RSA encryption. * params is modulus, public exp. */ int _gnutls_pkcs1_rsa_encrypt (gnutls_datum_t * ciphertext, const gnutls_datum_t * plaintext, bigint_t * params, unsigned params_len, unsigned btype) { unsigned int i, pad; int ret; opaque *edata, *ps; size_t k, psize; size_t mod_bits; gnutls_pk_params_st pk_params; gnutls_datum to_encrypt, encrypted; for (i = 0; i < params_len; i++) pk_params.params[i] = params[i]; pk_params.params_nr = params_len; mod_bits = _gnutls_mpi_get_nbits (params[0]); k = mod_bits / 8; if (mod_bits % 8 != 0) k++; if (plaintext->size > k - 11) { gnutls_assert (); return GNUTLS_E_PK_ENCRYPTION_FAILED; } edata = gnutls_malloc (k); if (edata == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } /* EB = 00||BT||PS||00||D * (use block type 'btype') */ edata[0] = 0; edata[1] = btype; psize = k - 3 - plaintext->size; ps = &edata[2]; switch (btype) { case 2: /* using public key */ if (params_len < RSA_PUBLIC_PARAMS) { gnutls_assert (); gnutls_free (edata); return GNUTLS_E_INTERNAL_ERROR; } ret = _gnutls_rnd (GNUTLS_RND_RANDOM, ps, psize); if (ret < 0) { gnutls_assert (); gnutls_free (edata); return ret; } for (i = 0; i < psize; i++) while (ps[i] == 0) { ret = _gnutls_rnd (GNUTLS_RND_RANDOM, &ps[i], 1); if (ret < 0) { gnutls_assert (); gnutls_free (edata); return ret; } } break; case 1: /* using private key */ if (params_len < RSA_PRIVATE_PARAMS) { gnutls_assert (); gnutls_free (edata); return GNUTLS_E_INTERNAL_ERROR; } for (i = 0; i < psize; i++) ps[i] = 0xff; break; default: gnutls_assert (); gnutls_free (edata); return GNUTLS_E_INTERNAL_ERROR; } ps[psize] = 0; memcpy (&ps[psize + 1], plaintext->data, plaintext->size); to_encrypt.data = edata; to_encrypt.size = k; if (btype == 2) /* encrypt */ ret = _gnutls_pk_encrypt (GNUTLS_PK_RSA, &encrypted, &to_encrypt, &pk_params); else /* sign */ ret = _gnutls_pk_sign (GNUTLS_PK_RSA, &encrypted, &to_encrypt, &pk_params); gnutls_free (edata); if (ret < 0) { gnutls_assert (); return ret; } psize = encrypted.size; if (psize < k) { /* padding psize */ pad = k - psize; psize = k; } else if (psize == k) { /* pad = 0; * no need to do anything else */ ciphertext->data = encrypted.data; ciphertext->size = encrypted.size; return 0; } else { /* psize > k !!! */ /* This is an impossible situation */ gnutls_assert (); _gnutls_free_datum (&encrypted); return GNUTLS_E_INTERNAL_ERROR; } ciphertext->data = gnutls_malloc (psize); if (ciphertext->data == NULL) { gnutls_assert (); _gnutls_free_datum (&encrypted); return GNUTLS_E_MEMORY_ERROR; } memcpy (&ciphertext->data[pad], encrypted.data, encrypted.size); for (i = 0; i < pad; i++) ciphertext->data[i] = 0; ciphertext->size = k; _gnutls_free_datum (&encrypted); return 0; }
int proc_rsa_export_client_kx (gnutls_session_t session, opaque * data, size_t _data_size) { gnutls_datum_t plaintext; gnutls_datum_t ciphertext; int ret, dsize; bigint_t *params; int params_len; int randomize_key = 0; ssize_t data_size = _data_size; if (gnutls_protocol_get_version (session) == GNUTLS_SSL3) { /* SSL 3.0 */ ciphertext.data = data; ciphertext.size = data_size; } else { /* TLS 1.0 */ DECR_LEN (data_size, 2); ciphertext.data = &data[2]; dsize = _gnutls_read_uint16 (data); if (dsize != data_size) { gnutls_assert (); return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; } ciphertext.size = dsize; } ret = _gnutls_get_private_rsa_params (session, ¶ms, ¶ms_len); if (ret < 0) { gnutls_assert (); return ret; } ret = _gnutls_pkcs1_rsa_decrypt (&plaintext, &ciphertext, params, params_len, 2); /* btype==2 */ if (ret < 0 || plaintext.size != GNUTLS_MASTER_SIZE) { /* In case decryption fails then don't inform * the peer. Just use a random key. (in order to avoid * attack against pkcs-1 formating). */ gnutls_assert (); _gnutls_audit_log ("auth_rsa: Possible PKCS #1 format attack\n"); randomize_key = 1; } else { /* If the secret was properly formatted, then * check the version number. */ if (_gnutls_get_adv_version_major (session) != plaintext.data[0] || _gnutls_get_adv_version_minor (session) != plaintext.data[1]) { /* No error is returned here, if the version number check * fails. We proceed normally. * That is to defend against the attack described in the paper * "Attacking RSA-based sessions in SSL/TLS" by Vlastimil Klima, * Ondej Pokorny and Tomas Rosa. */ gnutls_assert (); _gnutls_audit_log ("auth_rsa: Possible PKCS #1 version check format attack\n"); } } if (randomize_key != 0) { session->key->key.size = GNUTLS_MASTER_SIZE; session->key->key.data = gnutls_malloc (session->key->key.size); if (session->key->key.data == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } /* we do not need strong random numbers here. */ ret = _gnutls_rnd (GNUTLS_RND_NONCE, session->key->key.data, session->key->key.size); if (ret < 0) { gnutls_assert (); return ret; } } else { session->key->key.data = plaintext.data; session->key->key.size = plaintext.size; } /* This is here to avoid the version check attack * discussed above. */ session->key->key.data[0] = _gnutls_get_adv_version_major (session); session->key->key.data[1] = _gnutls_get_adv_version_minor (session); return 0; }
/* 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; } }
/* This is the actual encryption * Encrypts the given compressed datum, and puts the result to cipher_data, * which has cipher_size size. * return the actual encrypted data length. */ static int compressed_to_ciphertext (gnutls_session_t session, opaque * cipher_data, int cipher_size, gnutls_datum_t *compressed, content_type_t type, record_parameters_st * params) { uint8_t * tag_ptr = NULL; uint8_t pad; int length, length_to_encrypt, ret; opaque preamble[MAX_PREAMBLE_SIZE]; int preamble_size; int tag_size = _gnutls_auth_cipher_tag_len (¶ms->write.cipher_state); int blocksize = gnutls_cipher_get_block_size (params->cipher_algorithm); unsigned block_algo = _gnutls_cipher_is_block (params->cipher_algorithm); opaque *data_ptr; int ver = gnutls_protocol_get_version (session); int explicit_iv = _gnutls_version_has_explicit_iv (session->security_parameters.version); int auth_cipher = _gnutls_auth_cipher_is_aead(¶ms->write.cipher_state); int random_pad; /* We don't use long padding if requested or if we are in DTLS. */ if (session->internals.priorities.no_padding == 0 && (!IS_DTLS(session))) random_pad = 1; else random_pad = 0; _gnutls_hard_log("ENC[%p]: cipher: %s, MAC: %s, Epoch: %u\n", session, gnutls_cipher_get_name(params->cipher_algorithm), gnutls_mac_get_name(params->mac_algorithm), (unsigned int)params->epoch); preamble_size = make_preamble (UINT64DATA (params->write.sequence_number), type, compressed->size, ver, preamble); /* Calculate the encrypted length (padding etc.) */ length_to_encrypt = length = calc_enc_length (session, compressed->size, tag_size, &pad, random_pad, block_algo, auth_cipher, blocksize); if (length < 0) { return gnutls_assert_val(length); } /* copy the encrypted data to cipher_data. */ if (cipher_size < length) { return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); } data_ptr = cipher_data; if (explicit_iv) { if (block_algo == CIPHER_BLOCK) { /* copy the random IV. */ ret = _gnutls_rnd (GNUTLS_RND_NONCE, data_ptr, blocksize); if (ret < 0) return gnutls_assert_val(ret); _gnutls_auth_cipher_setiv(¶ms->write.cipher_state, data_ptr, blocksize); data_ptr += blocksize; cipher_data += blocksize; length_to_encrypt -= blocksize; } else if (auth_cipher) { uint8_t nonce[blocksize]; /* Values in AEAD are pretty fixed in TLS 1.2 for 128-bit block */ if (params->write.IV.data == NULL || params->write.IV.size != AEAD_IMPLICIT_DATA_SIZE) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); /* Instead of generating a new nonce on every packet, we use the * write.sequence_number (It is a MAY on RFC 5288). */ memcpy(nonce, params->write.IV.data, params->write.IV.size); memcpy(&nonce[AEAD_IMPLICIT_DATA_SIZE], UINT64DATA(params->write.sequence_number), 8); _gnutls_auth_cipher_setiv(¶ms->write.cipher_state, nonce, AEAD_IMPLICIT_DATA_SIZE+AEAD_EXPLICIT_DATA_SIZE); /* copy the explicit part */ memcpy(data_ptr, &nonce[AEAD_IMPLICIT_DATA_SIZE], AEAD_EXPLICIT_DATA_SIZE); data_ptr += AEAD_EXPLICIT_DATA_SIZE; cipher_data += AEAD_EXPLICIT_DATA_SIZE; /* In AEAD ciphers we don't encrypt the tag */ length_to_encrypt -= AEAD_EXPLICIT_DATA_SIZE + tag_size; } } else { /* AEAD ciphers have an explicit IV. Shouldn't be used otherwise. */ if (auth_cipher) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); } memcpy (data_ptr, compressed->data, compressed->size); data_ptr += compressed->size; if (tag_size > 0) { tag_ptr = data_ptr; data_ptr += tag_size; } if (block_algo == CIPHER_BLOCK && pad > 0) { memset (data_ptr, pad - 1, pad); } /* add the authenticate data */ _gnutls_auth_cipher_add_auth(¶ms->write.cipher_state, preamble, preamble_size); /* Actual encryption (inplace). */ ret = _gnutls_auth_cipher_encrypt_tag (¶ms->write.cipher_state, cipher_data, length_to_encrypt, tag_ptr, tag_size, compressed->size); if (ret < 0) return gnutls_assert_val(ret); return length; }
int RAND_bytes (unsigned char *buf, int num) { _gnutls_rnd (GNUTLS_RND_RANDOM, buf, num); return 1; }
/** * gnutls_heartbeat_ping: * @session: is a #gnutls_session_t structure. * @data_size: is the length of the ping payload. * @max_tries: if flags is %GNUTLS_HEARTBEAT_WAIT then this sets the number of retransmissions. Use zero for indefinite (until timeout). * @flags: if %GNUTLS_HEARTBEAT_WAIT then wait for pong or timeout instead of returning immediately. * * This function sends a ping to the peer. If the @flags is set * to %GNUTLS_HEARTBEAT_WAIT then it waits for a reply from the peer. * * Note that it is highly recommended to use this function with the * flag %GNUTLS_HEARTBEAT_WAIT, or you need to handle retransmissions * and timeouts manually. * * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code. * * Since: 3.1.2 **/ int gnutls_heartbeat_ping(gnutls_session_t session, size_t data_size, unsigned int max_tries, unsigned int flags) { int ret; unsigned int retries = 1, diff; struct timespec now; if (data_size > MAX_HEARTBEAT_LENGTH) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); if (gnutls_heartbeat_allowed (session, GNUTLS_HB_LOCAL_ALLOWED_TO_SEND) == 0) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); /* resume previous call if interrupted */ if (session->internals.record_send_buffer.byte_length > 0 && session->internals.record_send_buffer.head != NULL && session->internals.record_send_buffer.head->type == GNUTLS_HEARTBEAT) return _gnutls_io_write_flush(session); switch (session->internals.hb_state) { case SHB_SEND1: if (data_size > DEFAULT_PAYLOAD_SIZE) data_size -= DEFAULT_PAYLOAD_SIZE; else data_size = 0; _gnutls_buffer_reset(&session->internals.hb_local_data); ret = _gnutls_buffer_resize(&session->internals. hb_local_data, data_size); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_rnd(GNUTLS_RND_NONCE, session->internals.hb_local_data.data, data_size); if (ret < 0) return gnutls_assert_val(ret); gettime(&session->internals.hb_ping_start); session->internals.hb_local_data.length = data_size; session->internals.hb_state = SHB_SEND2; case SHB_SEND2: session->internals.hb_actual_retrans_timeout_ms = session->internals.hb_retrans_timeout_ms; retry: ret = heartbeat_send_data(session, session->internals.hb_local_data. data, session->internals.hb_local_data. length, HEARTBEAT_REQUEST); if (ret < 0) return gnutls_assert_val(ret); gettime(&session->internals.hb_ping_sent); if (!(flags & GNUTLS_HEARTBEAT_WAIT)) { session->internals.hb_state = SHB_SEND1; break; } session->internals.hb_state = SHB_RECV; case SHB_RECV: ret = _gnutls_recv_int(session, GNUTLS_HEARTBEAT, -1, NULL, 0, NULL, session->internals. hb_actual_retrans_timeout_ms); if (ret == GNUTLS_E_HEARTBEAT_PONG_RECEIVED) { session->internals.hb_state = SHB_SEND1; break; } else if (ret == GNUTLS_E_TIMEDOUT) { retries++; if (max_tries > 0 && retries > max_tries) { session->internals.hb_state = SHB_SEND1; return gnutls_assert_val(ret); } gettime(&now); diff = timespec_sub_ms(&now, &session->internals. hb_ping_start); if (diff > session->internals.hb_total_timeout_ms) { session->internals.hb_state = SHB_SEND1; return gnutls_assert_val(GNUTLS_E_TIMEDOUT); } session->internals.hb_actual_retrans_timeout_ms *= 2; session->internals.hb_actual_retrans_timeout_ms %= MAX_DTLS_TIMEOUT; session->internals.hb_state = SHB_SEND2; goto retry; } else if (ret < 0) { session->internals.hb_state = SHB_SEND1; return gnutls_assert_val(ret); } } return 0; }
/** * gnutls_pkcs12_generate_mac: * @pkcs12: should contain a gnutls_pkcs12_t structure * @pass: The password for the MAC * * This function will generate a MAC for the PKCS12 structure. * * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a * negative error value. **/ int gnutls_pkcs12_generate_mac (gnutls_pkcs12_t pkcs12, const char *pass) { opaque salt[8], key[20]; int result; const int iter = 1; digest_hd_st td1; gnutls_datum_t tmp = { NULL, 0 }; opaque sha_mac[20]; if (pkcs12 == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } /* Generate the salt. */ result = _gnutls_rnd (GNUTLS_RND_NONCE, salt, sizeof (salt)); if (result < 0) { gnutls_assert (); return result; } /* Write the salt into the structure. */ result = asn1_write_value (pkcs12->pkcs12, "macData.macSalt", salt, sizeof (salt)); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } /* write the iterations */ if (iter > 1) { result = _gnutls_x509_write_uint32 (pkcs12->pkcs12, "macData.iterations", iter); if (result < 0) { gnutls_assert (); goto cleanup; } } /* Generate the key. */ result = _gnutls_pkcs12_string_to_key (3 /*MAC*/, salt, sizeof (salt), iter, pass, sizeof (key), key); if (result < 0) { gnutls_assert (); goto cleanup; } /* Get the data to be MACed */ result = _decode_pkcs12_auth_safe (pkcs12->pkcs12, NULL, &tmp); if (result < 0) { gnutls_assert (); goto cleanup; } /* MAC the data */ result = _gnutls_hmac_init (&td1, GNUTLS_MAC_SHA1, key, sizeof (key)); if (result < 0) { gnutls_assert (); goto cleanup; } _gnutls_hmac (&td1, tmp.data, tmp.size); _gnutls_free_datum (&tmp); _gnutls_hmac_deinit (&td1, sha_mac); result = asn1_write_value (pkcs12->pkcs12, "macData.mac.digest", sha_mac, sizeof (sha_mac)); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } result = asn1_write_value (pkcs12->pkcs12, "macData.mac.digestAlgorithm.parameters", NULL, 0); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } result = asn1_write_value (pkcs12->pkcs12, "macData.mac.digestAlgorithm.algorithm", HASH_OID_SHA1, 1); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } return 0; cleanup: _gnutls_free_datum (&tmp); return result; }
/* This is the actual encryption * Encrypts the given compressed datum, and puts the result to cipher_data, * which has cipher_size size. * return the actual encrypted data length. */ static int compressed_to_ciphertext(gnutls_session_t session, uint8_t * cipher_data, int cipher_size, gnutls_datum_t * compressed, size_t min_pad, content_type_t type, record_parameters_st * params) { uint8_t pad; int length, ret; uint8_t preamble[MAX_PREAMBLE_SIZE]; int preamble_size; int tag_size = _gnutls_auth_cipher_tag_len(¶ms->write.cipher_state); int blocksize = _gnutls_cipher_get_block_size(params->cipher); unsigned block_algo = _gnutls_cipher_is_block(params->cipher); uint8_t *data_ptr; const version_entry_st *ver = get_version(session); int explicit_iv = _gnutls_version_has_explicit_iv(ver); int auth_cipher = _gnutls_auth_cipher_is_aead(¶ms->write.cipher_state); uint8_t nonce[MAX_CIPHER_BLOCK_SIZE]; unsigned iv_size; if (unlikely(ver == NULL)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); iv_size = _gnutls_cipher_get_implicit_iv_size(params->cipher); _gnutls_hard_log("ENC[%p]: cipher: %s, MAC: %s, Epoch: %u\n", session, _gnutls_cipher_get_name(params->cipher), _gnutls_mac_get_name(params->mac), (unsigned int) params->epoch); preamble_size = make_preamble(UINT64DATA (params->write.sequence_number), type, compressed->size, ver, preamble); /* Calculate the encrypted length (padding etc.) */ if (block_algo == CIPHER_BLOCK) { /* Call _gnutls_rnd() once. Get data used for the IV */ ret = _gnutls_rnd(GNUTLS_RND_NONCE, nonce, blocksize); if (ret < 0) return gnutls_assert_val(ret); pad = min_pad; length = calc_enc_length_block(session, ver, compressed->size, tag_size, &pad, auth_cipher, blocksize); } else { pad = 0; length = calc_enc_length_stream(session, compressed->size, tag_size, auth_cipher); } if (length < 0) return gnutls_assert_val(length); /* copy the encrypted data to cipher_data. */ if (cipher_size < length) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); data_ptr = cipher_data; if (explicit_iv) { /* TLS 1.1 or later */ if (block_algo == CIPHER_BLOCK) { /* copy the random IV. */ memcpy(data_ptr, nonce, blocksize); _gnutls_auth_cipher_setiv(¶ms->write. cipher_state, data_ptr, blocksize); data_ptr += blocksize; cipher_data += blocksize; } else if (auth_cipher) { /* Values in AEAD are pretty fixed in TLS 1.2 for 128-bit block */ if (params->write.IV.data == NULL || params->write.IV.size != AEAD_IMPLICIT_DATA_SIZE) return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR); /* Instead of generating a new nonce on every packet, we use the * write.sequence_number (It is a MAY on RFC 5288). */ memcpy(nonce, params->write.IV.data, params->write.IV.size); memcpy(&nonce[AEAD_IMPLICIT_DATA_SIZE], UINT64DATA(params->write.sequence_number), 8); _gnutls_auth_cipher_setiv(¶ms->write. cipher_state, nonce, AEAD_IMPLICIT_DATA_SIZE + AEAD_EXPLICIT_DATA_SIZE); /* copy the explicit part */ memcpy(data_ptr, &nonce[AEAD_IMPLICIT_DATA_SIZE], AEAD_EXPLICIT_DATA_SIZE); data_ptr += AEAD_EXPLICIT_DATA_SIZE; cipher_data += AEAD_EXPLICIT_DATA_SIZE; } else if (iv_size > 0) _gnutls_auth_cipher_setiv(¶ms->write. cipher_state, UINT64DATA(params->write. sequence_number), 8); } else { /* AEAD ciphers have an explicit IV. Shouldn't be used otherwise. */ if (auth_cipher) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); else if (block_algo == CIPHER_STREAM && iv_size > 0) _gnutls_auth_cipher_setiv(¶ms->write. cipher_state, UINT64DATA(params->write. sequence_number), 8); } _gnutls_auth_cipher_set_mac_nonce(¶ms->write.cipher_state, UINT64DATA(params->write. sequence_number), 8); /* add the authenticate data */ ret = _gnutls_auth_cipher_add_auth(¶ms->write.cipher_state, preamble, preamble_size); if (ret < 0) return gnutls_assert_val(ret); /* Actual encryption. */ ret = _gnutls_auth_cipher_encrypt2_tag(¶ms->write.cipher_state, compressed->data, compressed->size, cipher_data, cipher_size, pad); if (ret < 0) return gnutls_assert_val(ret); return length; }