is_binding = (cifs_chan_needs_reconnect(ses, server) &&
ses->ses_status == SES_GOOD); if (is_binding) { /* * If we are in the process of binding a new channel * to an existing session, use the master connection * session key
*/
memcpy(key, ses->smb3signingkey, SMB3_SIGN_KEY_SIZE);
spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock); goto out;
}
/* * Otherwise, use the channel key.
*/
for (i = 0; i < ses->chan_count; i++) {
chan = ses->chans + i; if (chan->server == server) {
memcpy(key, chan->signkey, SMB3_SIGN_KEY_SIZE);
spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock); goto out;
}
}
spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock);
cifs_dbg(VFS, "%s: Could not find channel signing key for session 0x%llx\n",
__func__, ses_id);
rc = -ENOENT;
spin_lock(&cifs_tcp_ses_lock);
ses = smb2_find_smb_ses_unlocked(server, ses_id); if (!ses) {
spin_unlock(&cifs_tcp_ses_lock); return NULL;
}
tcon = smb2_find_smb_sess_tcon_unlocked(ses, tid); if (!tcon) {
spin_unlock(&cifs_tcp_ses_lock);
cifs_put_smb_ses(ses); return NULL;
}
spin_unlock(&cifs_tcp_ses_lock); /* tcon already has a ref to ses, so we don't need ses anymore */
cifs_put_smb_ses(ses);
rc = crypto_shash_setkey(shash->tfm, key, sizeof(key)); if (rc) {
cifs_server_dbg(VFS, "%s: Could not update with response\n",
__func__); goto out;
}
rc = crypto_shash_init(shash); if (rc) {
cifs_server_dbg(VFS, "%s: Could not init sha256", __func__); goto out;
}
/* * For SMB2+, __cifs_calc_signature() expects to sign only the actual * data, that is, iov[0] should not contain a rfc1002 length. * * Sign the rfc1002 length prior to passing the data (iov[1-N]) down to * __cifs_calc_signature().
*/
drqst = *rqst; if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) {
rc = crypto_shash_update(shash, iov[0].iov_base,
iov[0].iov_len); if (rc) {
cifs_server_dbg(VFS, "%s: Could not update with payload\n",
__func__); goto out;
}
drqst.rq_iov++;
drqst.rq_nvec--;
}
rc = crypto_shash_setkey(server->secmech.hmacsha256->tfm,
ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); if (rc) {
cifs_server_dbg(VFS, "%s: Could not set with session key\n", __func__); goto smb3signkey_ret;
}
rc = crypto_shash_init(server->secmech.hmacsha256); if (rc) {
cifs_server_dbg(VFS, "%s: Could not init sign hmac\n", __func__); goto smb3signkey_ret;
}
rc = crypto_shash_update(server->secmech.hmacsha256, i, 4); if (rc) {
cifs_server_dbg(VFS, "%s: Could not update with n\n", __func__); goto smb3signkey_ret;
}
rc = crypto_shash_update(server->secmech.hmacsha256, label.iov_base, label.iov_len); if (rc) {
cifs_server_dbg(VFS, "%s: Could not update with label\n", __func__); goto smb3signkey_ret;
}
rc = crypto_shash_update(server->secmech.hmacsha256, &zero, 1); if (rc) {
cifs_server_dbg(VFS, "%s: Could not update with zero\n", __func__); goto smb3signkey_ret;
}
rc = crypto_shash_update(server->secmech.hmacsha256, context.iov_base, context.iov_len); if (rc) {
cifs_server_dbg(VFS, "%s: Could not update with context\n", __func__); goto smb3signkey_ret;
}
if ((server->cipher_type == SMB2_ENCRYPTION_AES256_CCM) ||
(server->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) {
rc = crypto_shash_update(server->secmech.hmacsha256, L256, 4);
} else {
rc = crypto_shash_update(server->secmech.hmacsha256, L128, 4);
} if (rc) {
cifs_server_dbg(VFS, "%s: Could not update with L\n", __func__); goto smb3signkey_ret;
}
rc = crypto_shash_final(server->secmech.hmacsha256, hashptr); if (rc) {
cifs_server_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__); goto smb3signkey_ret;
}
/* * All channels use the same encryption/decryption keys but * they have their own signing key. * * When we generate the keys, check if it is for a new channel * (binding) in which case we only need to generate a signing * key and store it in the channel as to not overwrite the * master connection signing key stored in the session
*/
if (is_binding) {
rc = generate_key(ses, ptriplet->signing.label,
ptriplet->signing.context,
ses->chans[chan_index].signkey,
SMB3_SIGN_KEY_SIZE); if (rc) return rc;
} else {
rc = generate_key(ses, ptriplet->signing.label,
ptriplet->signing.context,
ses->smb3signingkey,
SMB3_SIGN_KEY_SIZE); if (rc) return rc;
/* safe to access primary channel, since it will never go away */
spin_lock(&ses->chan_lock);
memcpy(ses->chans[chan_index].signkey, ses->smb3signingkey,
SMB3_SIGN_KEY_SIZE);
spin_unlock(&ses->chan_lock);
rc = smb3_get_sign_key(le64_to_cpu(shdr->SessionId), server, key); if (unlikely(rc)) {
cifs_server_dbg(FYI, "%s: Could not get signing key\n", __func__); return rc;
}
if (allocate_crypto) {
rc = cifs_alloc_hash("cmac(aes)", &shash); if (rc) return rc;
} else {
shash = server->secmech.aes_cmac;
}
rc = crypto_shash_setkey(shash->tfm, key, SMB2_CMACAES_SIZE); if (rc) {
cifs_server_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__); goto out;
}
/* * we already allocate aes_cmac when we init smb3 signing key, * so unlike smb2 case we do not have to check here if secmech are * initialized
*/
rc = crypto_shash_init(shash); if (rc) {
cifs_server_dbg(VFS, "%s: Could not init cmac aes\n", __func__); goto out;
}
/* * For SMB2+, __cifs_calc_signature() expects to sign only the actual * data, that is, iov[0] should not contain a rfc1002 length. * * Sign the rfc1002 length prior to passing the data (iov[1-N]) down to * __cifs_calc_signature().
*/
drqst = *rqst; if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) {
rc = crypto_shash_update(shash, iov[0].iov_base,
iov[0].iov_len); if (rc) {
cifs_server_dbg(VFS, "%s: Could not update with payload\n",
__func__); goto out;
}
drqst.rq_iov++;
drqst.rq_nvec--;
}
out: if (allocate_crypto)
cifs_free_hash(&shash); return rc;
}
/* must be called with server->srv_mutex held */ staticint
smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
{ int rc = 0; struct smb2_hdr *shdr; struct smb2_sess_setup_req *ssr; bool is_binding; bool is_signed;
shdr = (struct smb2_hdr *)rqst->rq_iov[0].iov_base;
ssr = (struct smb2_sess_setup_req *)shdr;
/* * BB what if signatures are supposed to be on for session but * server does not send one? BB
*/
/* Do not need to verify session setups with signature "BSRSPYL " */ if (memcmp(shdr->Signature, "BSRSPYL ", 8) == 0)
cifs_dbg(FYI, "dummy signature received for smb command 0x%x\n",
shdr->Command);
/* * Save off the original signature so we can modify the smb and check * our calculated signature against what the server sent.
*/
memcpy(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE);
/* * Set message id for the request. Should be called after wait_for_free_request * and when srv_mutex is held.
*/ staticinlinevoid
smb2_seq_num_into_buf(struct TCP_Server_Info *server, struct smb2_hdr *shdr)
{ unsignedint i, num = le16_to_cpu(shdr->CreditCharge);
shdr->MessageId = get_next_mid64(server); /* skip message numbers according to CreditCharge field */ for (i = 1; i < num; i++)
get_next_mid(server);
}
/* * The default is for the mid to be synchronous, so the * default callback just wakes up the current task.
*/
get_task_struct(current);
temp->creator = current;
temp->callback = cifs_wake_up_task;
temp->callback_data = current;
if (server->tcpStatus == CifsNeedReconnect) {
spin_unlock(&server->srv_lock);
cifs_dbg(FYI, "tcp session dead - return to caller to retry\n"); return -EAGAIN;
}
spin_lock(&ses->ses_lock); if (ses->ses_status == SES_NEW) { if ((shdr->Command != SMB2_SESSION_SETUP) &&
(shdr->Command != SMB2_NEGOTIATE)) {
spin_unlock(&ses->ses_lock); return -EAGAIN;
} /* else ok - we are setting up session */
}
if (ses->ses_status == SES_EXITING) { if (shdr->Command != SMB2_LOGOFF) {
spin_unlock(&ses->ses_lock); return -EAGAIN;
} /* else ok - we are shutting down the session */
}
spin_unlock(&ses->ses_lock);
dump_smb(mid->resp_buf, min_t(u32, 80, len)); /* convert the length into a more usable form */ if (len > 24 && server->sign && !mid->decrypted) { int rc;
rc = smb2_verify_signature(&rqst, server); if (rc)
cifs_server_dbg(VFS, "SMB signature verification returned error = %d\n",
rc);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.