/* Initializes the nonce level random generator. * * the @nonce_key must be provided. * * @init must be non zero on first initialization, and * zero on any subsequent reinitializations. */ static int nonce_rng_init(struct nonce_ctx_st *ctx, uint8_t nonce_key[NONCE_KEY_SIZE], unsigned nonce_key_size, unsigned init) { uint8_t iv[8]; int ret; if (init == 0) { /* use the previous key to generate IV as well */ memset(iv, 0, sizeof(iv)); /* to prevent valgrind from whinning */ salsa20r12_crypt(&ctx->ctx, sizeof(iv), iv, iv); /* Add key continuity by XORing the new key with data generated * from the old key */ salsa20r12_crypt(&ctx->ctx, nonce_key_size, nonce_key, nonce_key); } else { ctx->forkid = _gnutls_get_forkid(); /* when initializing read the IV from the system randomness source */ ret = _rnd_get_system_entropy(iv, sizeof(iv)); if (ret < 0) return gnutls_assert_val(ret); } salsa20_set_key(&ctx->ctx, nonce_key_size, nonce_key); salsa20_set_iv(&ctx->ctx, iv); zeroize_key(nonce_key, nonce_key_size); ctx->counter = 0; return 0; }
/* Initializes the nonce level random generator. * * the @new_key must be provided. * * @init must be non zero on first initialization, and * zero on any subsequent reinitializations. */ static int single_prng_init(struct prng_ctx_st *ctx, uint8_t new_key[PRNG_KEY_SIZE], unsigned new_key_size, unsigned init) { uint8_t nonce[CHACHA_NONCE_SIZE]; memset(nonce, 0, sizeof(nonce)); /* to prevent valgrind from whinning */ if (init == 0) { /* use the previous key to generate IV as well */ chacha_crypt(&ctx->ctx, sizeof(nonce), nonce, nonce); /* Add key continuity by XORing the new key with data generated * from the old key */ chacha_crypt(&ctx->ctx, new_key_size, new_key, new_key); } else { struct timespec now; /* current time */ ctx->forkid = _gnutls_get_forkid(); gettime(&now); memcpy(nonce, &now, MIN(sizeof(nonce), sizeof(now))); ctx->last_reseed = now.tv_sec; } chacha_set_key(&ctx->ctx, new_key); chacha_set_nonce(&ctx->ctx, nonce); zeroize_key(new_key, new_key_size); ctx->counter = 0; return 0; }
static void _rngfips_deinit(void *_ctx) { struct fips_ctx *ctx = _ctx; gnutls_mutex_deinit(&rnd_mutex); rnd_mutex = NULL; zeroize_key(ctx, sizeof(*ctx)); free(ctx); }
/* this function opens the tpasswd.conf file and reads the g and n * values. They are put in the entry. */ static int pwd_read_conf(const char *pconf_file, SRP_PWD_ENTRY * entry, int idx) { FILE *fd; char *line = NULL; size_t line_size = 0; unsigned i, len; char indexstr[10]; int ret; snprintf(indexstr, sizeof(indexstr), "%u", (unsigned int) idx); fd = fopen(pconf_file, "r"); if (fd == NULL) { gnutls_assert(); return GNUTLS_E_FILE_ERROR; } len = strlen(indexstr); while (getline(&line, &line_size, fd) > 0) { /* move to first ':' */ i = 0; while ((i < line_size) && (line[i] != ':') && (line[i] != '\0')) { i++; } if (strncmp(indexstr, line, MAX(i, len)) == 0) { if ((idx = parse_tpasswd_conf_values(entry, line)) >= 0) { ret = 0; goto cleanup; } else { ret = GNUTLS_E_SRP_PWD_ERROR; goto cleanup; } } } ret = GNUTLS_E_SRP_PWD_ERROR; cleanup: zeroize_key(line, line_size); free(line); fclose(fd); return ret; }
static int drbg_init(struct drbg_aes_ctx *ctx) { uint8_t buffer[DRBG_AES_SEED_SIZE]; int ret; /* Get a key from the standard RNG or from the entropy source. */ ret = _rnd_get_system_entropy(buffer, sizeof(buffer)); if (ret < 0) return gnutls_assert_val(ret); ret = drbg_aes_init(ctx, sizeof(buffer), buffer, PSTRING_SIZE, (void*)PSTRING); if (ret == 0) return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED); zeroize_key(buffer, sizeof(buffer)); return 0; }
/* Returns the PSK key of the given user. * If the user doesn't exist a random password is returned instead. */ int _gnutls_psk_pwd_find_entry(gnutls_session_t session, char *username, gnutls_datum_t * psk) { gnutls_psk_server_credentials_t cred; FILE *fd; char *line = NULL; size_t line_size = 0; unsigned i, len; int ret; cred = (gnutls_psk_server_credentials_t) _gnutls_get_cred(session, GNUTLS_CRD_PSK); if (cred == NULL) { gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } /* if the callback which sends the parameters is * set, use it. */ if (cred->pwd_callback != NULL) { ret = cred->pwd_callback(session, username, psk); if (ret == 1) { /* the user does not exist */ ret = _randomize_psk(psk); if (ret < 0) { gnutls_assert(); return ret; } return 0; } if (ret < 0) { gnutls_assert(); return GNUTLS_E_SRP_PWD_ERROR; } return 0; } /* The callback was not set. Proceed. */ if (cred->password_file == NULL) { gnutls_assert(); return GNUTLS_E_SRP_PWD_ERROR; } /* Open the selected password file. */ fd = fopen(cred->password_file, "r"); if (fd == NULL) { gnutls_assert(); return GNUTLS_E_SRP_PWD_ERROR; } len = strlen(username); while (getline(&line, &line_size, fd) > 0) { /* move to first ':' */ i = 0; while ((i < line_size) && (line[i] != '\0') && (line[i] != ':')) { i++; } if (strncmp(username, line, MAX(i, len)) == 0) { ret = pwd_put_values(psk, line); if (ret < 0) { gnutls_assert(); ret = GNUTLS_E_SRP_PWD_ERROR; goto cleanup; } ret = 0; goto cleanup; } } /* user was not found. Fake him. */ ret = _randomize_psk(psk); if (ret < 0) { goto cleanup; } ret = 0; cleanup: if (fd != NULL) fclose(fd); zeroize_key(line, line_size); free(line); return ret; }
/** * gnutls_x509_privkey_import_openssl: * @key: The structure to store the parsed key * @data: The DER or PEM encoded key. * @password: the password to decrypt the key (if it is encrypted). * * This function will convert the given PEM encrypted to * the native gnutls_x509_privkey_t format. The * output will be stored in @key. * * The @password should be in ASCII. If the password is not provided * or wrong then %GNUTLS_E_DECRYPTION_FAILED will be returned. * * If the Certificate is PEM encoded it should have a header of * "PRIVATE KEY" and the "DEK-Info" header. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_x509_privkey_import_openssl(gnutls_x509_privkey_t key, const gnutls_datum_t * data, const char *password) { gnutls_cipher_hd_t handle; gnutls_cipher_algorithm_t cipher = GNUTLS_CIPHER_UNKNOWN; gnutls_datum_t b64_data; gnutls_datum_t salt, enc_key; unsigned char *key_data; size_t key_data_size; const char *pem_header = (void *) data->data; const char *pem_header_start = (void *) data->data; ssize_t pem_header_size; int ret; unsigned int i, iv_size, l; pem_header_size = data->size; pem_header = memmem(pem_header, pem_header_size, "PRIVATE KEY---", 14); if (pem_header == NULL) { gnutls_assert(); return GNUTLS_E_PARSING_ERROR; } pem_header_size -= (ptrdiff_t) (pem_header - pem_header_start); pem_header = memmem(pem_header, pem_header_size, "DEK-Info: ", 10); if (pem_header == NULL) { gnutls_assert(); return GNUTLS_E_PARSING_ERROR; } pem_header_size = data->size - (ptrdiff_t) (pem_header - pem_header_start) - 10; pem_header += 10; for (i = 0; i < sizeof(pem_ciphers) / sizeof(pem_ciphers[0]); i++) { l = strlen(pem_ciphers[i].name); if (!strncmp(pem_header, pem_ciphers[i].name, l) && pem_header[l] == ',') { pem_header += l + 1; cipher = pem_ciphers[i].cipher; break; } } if (cipher == GNUTLS_CIPHER_UNKNOWN) { _gnutls_debug_log ("Unsupported PEM encryption type: %.10s\n", pem_header); gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } iv_size = gnutls_cipher_get_iv_size(cipher); salt.size = iv_size; salt.data = gnutls_malloc(salt.size); if (!salt.data) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); for (i = 0; i < salt.size * 2; i++) { unsigned char x; const char *c = &pem_header[i]; if (*c >= '0' && *c <= '9') x = (*c) - '0'; else if (*c >= 'A' && *c <= 'F') x = (*c) - 'A' + 10; else { gnutls_assert(); /* Invalid salt in encrypted PEM file */ ret = GNUTLS_E_INVALID_REQUEST; goto out_salt; } if (i & 1) salt.data[i / 2] |= x; else salt.data[i / 2] = x << 4; } pem_header += salt.size * 2; if (*pem_header != '\r' && *pem_header != '\n') { gnutls_assert(); ret = GNUTLS_E_INVALID_REQUEST; goto out_salt; } while (*pem_header == '\n' || *pem_header == '\r') pem_header++; ret = _gnutls_base64_decode((const void *) pem_header, pem_header_size, &b64_data); if (ret < 0) { gnutls_assert(); goto out_salt; } if (b64_data.size < 16) { /* Just to be sure our parsing is OK */ gnutls_assert(); ret = GNUTLS_E_PARSING_ERROR; goto out_b64; } ret = GNUTLS_E_MEMORY_ERROR; enc_key.size = gnutls_cipher_get_key_size(cipher); enc_key.data = gnutls_malloc(enc_key.size); if (!enc_key.data) { ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); goto out_b64; } key_data_size = b64_data.size; key_data = gnutls_malloc(key_data_size); if (!key_data) { ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); goto out_enc_key; } while (1) { memcpy(key_data, b64_data.data, key_data_size); ret = openssl_hash_password(password, &enc_key, &salt); if (ret < 0) { gnutls_assert(); goto out; } ret = gnutls_cipher_init(&handle, cipher, &enc_key, &salt); if (ret < 0) { gnutls_assert(); gnutls_cipher_deinit(handle); goto out; } ret = gnutls_cipher_decrypt(handle, key_data, key_data_size); gnutls_cipher_deinit(handle); if (ret < 0) { gnutls_assert(); goto out; } /* We have to strip any padding to accept it. So a bit more ASN.1 parsing for us. */ if (key_data[0] == 0x30) { gnutls_datum_t key_datum; unsigned int blocksize = gnutls_cipher_get_block_size(cipher); unsigned int keylen = key_data[1]; unsigned int ofs = 2; if (keylen & 0x80) { int lenlen = keylen & 0x7f; keylen = 0; if (lenlen > 3) { gnutls_assert(); goto fail; } while (lenlen) { keylen <<= 8; keylen |= key_data[ofs++]; lenlen--; } } keylen += ofs; /* If there appears to be more padding than required, fail */ if (key_data_size - keylen > blocksize) { gnutls_assert(); goto fail; } /* If the padding bytes aren't all equal to the amount of padding, fail */ ofs = keylen; while (ofs < key_data_size) { if (key_data[ofs] != key_data_size - keylen) { gnutls_assert(); goto fail; } ofs++; } key_datum.data = key_data; key_datum.size = keylen; ret = gnutls_x509_privkey_import(key, &key_datum, GNUTLS_X509_FMT_DER); if (ret == 0) goto out; } fail: ret = GNUTLS_E_DECRYPTION_FAILED; goto out; } out: zeroize_key(key_data, key_data_size); gnutls_free(key_data); out_enc_key: _gnutls_free_key_datum(&enc_key); out_b64: gnutls_free(b64_data.data); out_salt: gnutls_free(salt.data); return ret; }
static void wrap_nettle_mpi_clear(bigint_t a) { zeroize_key(TOMPZ(a)[0]._mp_d, TOMPZ(a)[0]._mp_alloc * sizeof(mp_limb_t)); }
static void ecc_point_zclear (struct ecc_point *p) { zeroize_key(p->p, ecc_size_a(p->ecc)*sizeof(mp_limb_t)); ecc_point_clear(p); }
static void ecc_scalar_zclear (struct ecc_scalar *s) { zeroize_key(s->p, ecc_size(s->ecc)*sizeof(mp_limb_t)); ecc_scalar_clear(s); }
int _gnutls_srp_pwd_read_entry(gnutls_session_t state, char *username, SRP_PWD_ENTRY ** _entry) { gnutls_srp_server_credentials_t cred; FILE *fd = NULL; char *line = NULL; size_t line_size = 0; unsigned i, len; int ret; int idx; SRP_PWD_ENTRY *entry = NULL; *_entry = gnutls_calloc(1, sizeof(SRP_PWD_ENTRY)); if (*_entry == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } entry = *_entry; cred = (gnutls_srp_server_credentials_t) _gnutls_get_cred(state, GNUTLS_CRD_SRP); if (cred == NULL) { gnutls_assert(); ret = GNUTLS_E_INSUFFICIENT_CREDENTIALS; goto cleanup; } /* if the callback which sends the parameters is * set, use it. */ if (cred->pwd_callback != NULL) { ret = cred->pwd_callback(state, username, &entry->salt, &entry->v, &entry->g, &entry->n); if (ret == 1) { /* the user does not exist */ if (entry->g.size != 0 && entry->n.size != 0) { ret = _randomize_pwd_entry(entry, cred, username); if (ret < 0) { gnutls_assert(); goto cleanup; } return 0; } else { gnutls_assert(); ret = -1; /* error in the callback */ } } if (ret < 0) { gnutls_assert(); ret = GNUTLS_E_SRP_PWD_ERROR; goto cleanup; } return 0; } /* The callback was not set. Proceed. */ if (cred->password_file == NULL) { gnutls_assert(); ret = GNUTLS_E_SRP_PWD_ERROR; goto cleanup; } /* Open the selected password file. */ fd = fopen(cred->password_file, "r"); if (fd == NULL) { gnutls_assert(); ret = GNUTLS_E_SRP_PWD_ERROR; goto cleanup; } len = strlen(username); while (getline(&line, &line_size, fd) > 0) { /* move to first ':' */ i = 0; while ((i < line_size) && (line[i] != '\0') && (line[i] != ':')) { i++; } if (strncmp(username, line, MAX(i, len)) == 0) { if ((idx = parse_tpasswd_values(entry, line)) >= 0) { /* Keep the last index in memory, so we can retrieve fake parameters (g,n) * when the user does not exist. */ if (pwd_read_conf (cred->password_conf_file, entry, idx) == 0) { ret = 0; goto found; } else { gnutls_assert(); ret = GNUTLS_E_SRP_PWD_ERROR; goto cleanup; } } else { gnutls_assert(); ret = GNUTLS_E_SRP_PWD_ERROR; goto cleanup; } } } /* user was not found. Fake him. Actually read the g,n values from * the last index found and randomize the entry. */ if (pwd_read_conf(cred->password_conf_file, entry, 1) == 0) { ret = _randomize_pwd_entry(entry, cred, username); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = 0; goto found; } ret = GNUTLS_E_SRP_PWD_ERROR; cleanup: gnutls_assert(); _gnutls_srp_entry_free(entry); found: zeroize_key(line, line_size); free(line); if (fd) fclose(fd); return ret; }