/* * sysctl helper routine for kern.urandom node. Picks a random number * for you. */ static int sysctl_kern_urnd(SYSCTLFN_ARGS) { static ONCE_DECL(control); int v, rv; RUN_ONCE(&control, makeprng); rv = cprng_strong(sysctl_prng, &v, sizeof(v), 0); if (rv == sizeof(v)) { struct sysctlnode node = *rnode; node.sysctl_data = &v; return (sysctl_lookup(SYSCTLFN_CALL(&node))); } else return (EIO); /*XXX*/ }
int assemble_security_parameters(connection_t *conn, ccb_t *ccb, pdu_t *rx_pdu, pdu_t *tx_pdu) { negotiation_state_t *state = (negotiation_state_t *) ccb->temp_data; iscsi_login_parameters_t *par = conn->login_par; negotiation_parameter_t rxp, *cpar; uint8_t *rxpars; int rc, next; uint8_t identifier = 0; uint8_t *challenge = NULL; int challenge_size = 0; uint8_t *response = NULL; int response_size = 0; state->num_pars = 0; next = 0; rxpars = (uint8_t *) rx_pdu->temp_data; if (rxpars == NULL) { DEBOUT(("No received parameters!\n")); return ISCSI_STATUS_NEGOTIATION_ERROR; } /* Note: There are always at least 2 extra bytes past temp_data_len */ rxpars[rx_pdu->temp_data_len] = '\0'; rxpars[rx_pdu->temp_data_len + 1] = '\0'; while (*rxpars) { if ((rxpars = get_parameter(rxpars, &rxp)) == NULL) { DEBOUT(("get_parameter returned error\n")); return ISCSI_STATUS_NEGOTIATION_ERROR; } state->kflags[rxp.key] |= NS_RECEIVED; switch (rxp.key) { case K_AuthMethod: if (state->auth_state != AUTH_INITIAL) { DEBOUT(("AuthMethod received, auth_state = %d\n", state->auth_state)); return ISCSI_STATUS_NEGOTIATION_ERROR; } /* Note: if the selection is None, we shouldn't be here, * the target should have transited the state to op-neg. */ if (rxp.val.nval[0] != ISCSI_AUTH_CHAP) { DEBOUT(("AuthMethod isn't CHAP (%d)\n", rxp.val.nval[0])); return ISCSI_STATUS_NEGOTIATION_ERROR; } state->auth_state = AUTH_METHOD_SELECTED; state->auth_alg = rxp.val.nval[0]; break; case K_Auth_CHAP_Algorithm: if (state->auth_state != AUTH_CHAP_ALG_SENT || rxp.val.nval[0] != 5) { DEBOUT(("Bad algorithm, auth_state = %d, alg %d\n", state->auth_state, rxp.val.nval[0])); return ISCSI_STATUS_NEGOTIATION_ERROR; } break; case K_Auth_CHAP_Challenge: if (state->auth_state != AUTH_CHAP_ALG_SENT || !rxp.list_num) { DEBOUT(("Bad Challenge, auth_state = %d, len %d\n", state->auth_state, rxp.list_num)); return ISCSI_STATUS_NEGOTIATION_ERROR; } challenge = rxp.val.sval; challenge_size = rxp.list_num; break; case K_Auth_CHAP_Identifier: if (state->auth_state != AUTH_CHAP_ALG_SENT) { DEBOUT(("Bad ID, auth_state = %d, id %d\n", state->auth_state, rxp.val.nval[0])); return ISCSI_STATUS_NEGOTIATION_ERROR; } identifier = (uint8_t) rxp.val.nval[0]; break; case K_Auth_CHAP_Name: if (state->auth_state != AUTH_CHAP_RSP_SENT) { DEBOUT(("Bad Name, auth_state = %d, name <%s>\n", state->auth_state, rxp.val.sval)); return ISCSI_STATUS_NEGOTIATION_ERROR; } /* what do we do with the name?? */ break; case K_Auth_CHAP_Response: if (state->auth_state != AUTH_CHAP_RSP_SENT) { DEBOUT(("Bad Response, auth_state = %d, size %d\n", state->auth_state, rxp.list_num)); return ISCSI_STATUS_NEGOTIATION_ERROR; } response = rxp.val.sval; response_size = rxp.list_num; if (response_size != CHAP_MD5_SIZE) return ISCSI_STATUS_NEGOTIATION_ERROR; break; default: rc = eval_parameter(conn, state, &rxp); if (rc) return rc; break; } } switch (state->auth_state) { case AUTH_INITIAL: DEBOUT(("Didn't receive Method\n")); return ISCSI_STATUS_NEGOTIATION_ERROR; case AUTH_METHOD_SELECTED: set_key_n(state, K_Auth_CHAP_Algorithm, 5); state->auth_state = AUTH_CHAP_ALG_SENT; next = -1; break; case AUTH_CHAP_ALG_SENT: if (!RX(state, K_Auth_CHAP_Algorithm) || !RX(state, K_Auth_CHAP_Identifier) || !RX(state, K_Auth_CHAP_Challenge)) { DEBOUT(("Didn't receive all parameters\n")); return ISCSI_STATUS_NEGOTIATION_ERROR; } set_key_s(state, K_Auth_CHAP_Name, state->user_name); chap_md5_response(state->temp_buf, identifier, state->password, challenge, challenge_size); cpar = set_key_s(state, K_Auth_CHAP_Response, state->temp_buf); if (cpar != NULL) cpar->list_num = CHAP_MD5_SIZE; if (par->auth_info.mutual_auth) { if (!state->target_password[0]) { DEBOUT(("No target password with mutual authentication!\n")); return ISCSI_STATUS_PARAMETER_MISSING; } cprng_strong(kern_cprng, &state->temp_buf[CHAP_MD5_SIZE], CHAP_CHALLENGE_LEN + 1, 0); set_key_n(state, K_Auth_CHAP_Identifier, state->temp_buf[CHAP_MD5_SIZE]); cpar = set_key_s(state, K_Auth_CHAP_Challenge, &state->temp_buf[CHAP_MD5_SIZE + 1]); if (cpar != NULL) cpar->list_num = CHAP_CHALLENGE_LEN; next = -1; } state->auth_state = AUTH_CHAP_RSP_SENT; break; case AUTH_CHAP_RSP_SENT: /* we can only be here for mutual authentication */ if (!par->auth_info.mutual_auth || response == NULL) { DEBOUT(("Mutual authentication not requested\n")); return ISCSI_STATUS_NEGOTIATION_ERROR; } chap_md5_response(state->temp_buf, state->temp_buf[CHAP_MD5_SIZE], state->password, &state->temp_buf[CHAP_MD5_SIZE + 1], CHAP_CHALLENGE_LEN); if (memcmp(state->temp_buf, response, response_size)) { DEBOUT(("Mutual authentication mismatch\n")); return ISCSI_STATUS_AUTHENTICATION_FAILED; } break; default: break; } complete_pars(state, tx_pdu); return next; }
static int rnd_read(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred, int flags) { int error = 0; DPRINTF(RND_DEBUG_READ, ("Random: Read of %zu requested, flags 0x%08x\n", uio->uio_resid, flags)); if (uio->uio_resid == 0) return 0; struct rnd_ctx *const ctx = fp->f_data; uint8_t *const buf = pool_cache_get(rnd_temp_buffer_cache, PR_WAITOK); /* * Choose a CPRNG to use -- either the per-open CPRNG, if this * is /dev/random or a long read, or the per-CPU one otherwise. * * XXX NIST_BLOCK_KEYLEN_BYTES is a detail of the cprng(9) * implementation and as such should not be mentioned here. */ struct cprng_strong *const cprng = ((ctx->rc_hard || (uio->uio_resid > NIST_BLOCK_KEYLEN_BYTES))? rnd_ctx_cprng(ctx) : rnd_percpu_cprng()); /* * Generate the data in RND_TEMP_BUFFER_SIZE chunks. */ while (uio->uio_resid > 0) { const size_t n_req = MIN(uio->uio_resid, RND_TEMP_BUFFER_SIZE); CTASSERT(RND_TEMP_BUFFER_SIZE <= CPRNG_MAX_LEN); const size_t n_read = cprng_strong(cprng, buf, n_req, ((ctx->rc_hard && ISSET(fp->f_flag, FNONBLOCK))? FNONBLOCK : 0)); /* * Equality will hold unless this is /dev/random, in * which case we get only as many bytes as are left * from the CPRNG's `information-theoretic strength' * since the last rekey. */ KASSERT(n_read <= n_req); KASSERT(ctx->rc_hard || (n_read == n_req)); error = uiomove(buf, n_read, uio); if (error) goto out; /* * Do at most one iteration for /dev/random and return * a short read without hanging further. Hanging * breaks applications worse than short reads. Reads * can't be zero unless nonblocking from /dev/random; * in that case, ask caller to retry, instead of just * returning zero bytes, which means EOF. */ KASSERT((0 < n_read) || (ctx->rc_hard && ISSET(fp->f_flag, FNONBLOCK))); if (ctx->rc_hard) { if (n_read == 0) error = EAGAIN; goto out; } } out: pool_cache_put(rnd_temp_buffer_cache, buf); return error; }