int __cifs_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, char *signature, struct shash_desc *shash)
{ int i;
ssize_t rc; struct kvec *iov = rqst->rq_iov; int n_vec = rqst->rq_nvec;
/* iov[0] is actual data and not the rfc1002 length for SMB2+ */ if (!is_smb1(server)) { if (iov[0].iov_len <= 4) return -EIO;
i = 0;
} else { if (n_vec < 2 || iov[0].iov_len != 4) return -EIO;
i = 1; /* skip rfc1002 length */
}
for (; i < n_vec; i++) { if (iov[i].iov_len == 0) continue; if (iov[i].iov_base == NULL) {
cifs_dbg(VFS, "null iovec entry\n"); return -EIO;
}
rc = crypto_shash_update(shash,
iov[i].iov_base, iov[i].iov_len); if (rc) {
cifs_dbg(VFS, "%s: Could not update with payload\n",
__func__); return rc;
}
}
if (!rqst->rq_iov || !signature || !server) return -EINVAL;
rc = cifs_alloc_hash("md5", &server->secmech.md5); if (rc) return -1;
rc = crypto_shash_init(server->secmech.md5); if (rc) {
cifs_dbg(VFS, "%s: Could not init md5\n", __func__); return rc;
}
rc = crypto_shash_update(server->secmech.md5,
server->session_key.response, server->session_key.len); if (rc) {
cifs_dbg(VFS, "%s: Could not update with response\n", __func__); return rc;
}
/* must be called with server->srv_mutex held */ int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
__u32 *pexpected_response_sequence_number)
{ int rc = 0; char smb_signature[20]; struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
/* must be called with server->srv_mutex held */ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
__u32 *pexpected_response_sequence_number)
{ struct kvec iov[2];
if (cifs_pdu == NULL || server == NULL) return -EINVAL;
if (!server->session_estab) return0;
if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) { struct smb_com_lock_req *pSMB =
(struct smb_com_lock_req *)cifs_pdu; if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE) return0;
}
/* 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(cifs_pdu->Signature.SecuritySignature, "BSRSPYL ", 8) == 0)
cifs_dbg(FYI, "dummy signature received for smb command 0x%x\n",
cifs_pdu->Command);
/* save off the original signature so we can modify the smb and check
its signature against what the server sent */
memcpy(server_response_sig, cifs_pdu->Signature.SecuritySignature, 8);
av_for_each_entry(ses, av) {
len = AV_LEN(av); if (AV_TYPE(av) != type || !len) continue; if (!IS_ALIGNED(len, sizeof(__le16))) {
cifs_dbg(VFS | ONCE, "%s: bad length(%u) for type %u\n",
__func__, len, type); continue;
}
nlen = len / sizeof(__le16); if (nlen <= maxlen) {
++nlen;
*name = kmalloc(nlen, GFP_KERNEL); if (!*name) return -ENOMEM;
cifs_from_utf16(*name, AV_DATA_PTR(av), nlen,
len, nlsc, NO_MAP_UNI_RSVD); break;
}
} return0;
}
/* Server has provided av pairs/target info in the type 2 challenge *packetandwehavepluckeditandstoredwithinsmbsession. *Weparsethatblobheretofindtheservergiventimestamp *aspartofntlmv2authentication(orlocalcurrenttimeas *defaultincaseoffailure)
*/ static __le64 find_timestamp(struct cifs_ses *ses)
{ struct ntlmssp2_name *av; struct timespec64 ts;
/* calculate md4 hash of password */
E_md4hash(ses->password, nt_hash, nls_cp);
rc = crypto_shash_setkey(hmacmd5->tfm, nt_hash, CIFS_NTHASH_SIZE); if (rc) {
cifs_dbg(VFS, "%s: Could not set NT hash as a key, rc=%d\n", __func__, rc); return rc;
}
rc = crypto_shash_init(hmacmd5); if (rc) {
cifs_dbg(VFS, "%s: Could not init HMAC-MD5, rc=%d\n", __func__, rc); return rc;
}
/* convert ses->user_name to unicode */
len = ses->user_name ? strlen(ses->user_name) : 0;
user = kmalloc(2 + (len * 2), GFP_KERNEL); if (user == NULL) return -ENOMEM;
if (len) {
len = cifs_strtoUTF16(user, ses->user_name, len, nls_cp);
UniStrupr(user);
} else {
*(u16 *)user = 0;
}
rc = crypto_shash_update(hmacmd5, (char *)user, 2 * len);
kfree(user); if (rc) {
cifs_dbg(VFS, "%s: Could not update with user, rc=%d\n", __func__, rc); return rc;
}
/* convert ses->domainName to unicode and uppercase */ if (ses->domainName) {
len = strlen(ses->domainName);
len = cifs_strtoUTF16((__le16 *)domain, ses->domainName, len,
nls_cp);
rc = crypto_shash_update(hmacmd5, (char *)domain, 2 * len);
kfree(domain); if (rc) {
cifs_dbg(VFS, "%s: Could not update with domain, rc=%d\n", __func__, rc); return rc;
}
} else { /* We use ses->ip_addr if no domain name available */
len = strlen(ses->ip_addr);
server = kmalloc(2 + (len * 2), GFP_KERNEL); if (server == NULL) return -ENOMEM;
len = cifs_strtoUTF16((__le16 *)server, ses->ip_addr, len, nls_cp);
rc = crypto_shash_update(hmacmd5, (char *)server, 2 * len);
kfree(server); if (rc) {
cifs_dbg(VFS, "%s: Could not update with server, rc=%d\n", __func__, rc); return rc;
}
}
rc = crypto_shash_final(hmacmd5, ntlmv2_hash); if (rc)
cifs_dbg(VFS, "%s: Could not generate MD5 hash, rc=%d\n", __func__, rc);
/* The MD5 hash starts at challenge_key.key */
hash_len = ses->auth_key.len - (CIFS_SESS_KEY_SIZE +
offsetof(struct ntlmv2_resp, challenge.key[0]));
rc = crypto_shash_setkey(hmacmd5->tfm, ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); if (rc) {
cifs_dbg(VFS, "%s: Could not set NTLMv2 hash as a key, rc=%d\n", __func__, rc); return rc;
}
rc = crypto_shash_init(hmacmd5); if (rc) {
cifs_dbg(VFS, "%s: Could not init HMAC-MD5, rc=%d\n", __func__, rc); return rc;
}
rc = crypto_shash_update(hmacmd5, ntlmv2->challenge.key, hash_len); if (rc) {
cifs_dbg(VFS, "%s: Could not update with response, rc=%d\n", __func__, rc); return rc;
}
/* Note that the MD5 digest over writes anon.challenge_key.key */
rc = crypto_shash_final(hmacmd5, ntlmv2->ntlmv2_hash); if (rc)
cifs_dbg(VFS, "%s: Could not generate MD5 hash, rc=%d\n", __func__, rc);
if (nls_cp == NULL) {
cifs_dbg(VFS, "%s called with nls_cp==NULL\n", __func__); return -EINVAL;
}
if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) { if (!ses->domainName) { if (ses->domainAuto) { /* *Domain(workgroup)hasn'tbeenspecifiedin *mountoptions,sotrytofinditin *CHALLENGE_MESSAGEmessageandthenuseitas *partofNTLMv2authentication.
*/
rc = find_av_name(ses, NTLMSSP_AV_NB_DOMAIN_NAME,
&ses->domainName,
CIFS_MAX_DOMAINNAME_LEN); if (rc) goto setup_ntlmv2_rsp_ret;
} else {
ses->domainName = kstrdup("", GFP_KERNEL); if (!ses->domainName) {
rc = -ENOMEM; goto setup_ntlmv2_rsp_ret;
}
}
}
rc = find_av_name(ses, NTLMSSP_AV_DNS_DOMAIN_NAME,
&ses->dns_dom, CIFS_MAX_DOMAINNAME_LEN); if (rc) goto setup_ntlmv2_rsp_ret;
} else {
rc = build_avpair_blob(ses, nls_cp); if (rc) {
cifs_dbg(VFS, "error %d building av pair blob\n", rc); goto setup_ntlmv2_rsp_ret;
}
}
/* Must be within 5 minutes of the server (or in range +/-2h *incaseofMacOSX),sosimplycarryoverservertimestamp *(asWindows7does)
*/
rsp_timestamp = find_timestamp(ses);
get_random_bytes(&cc, sizeof(cc));
rc = cifs_alloc_hash("hmac(md5)", &hmacmd5); if (rc) {
cifs_dbg(VFS, "Could not allocate HMAC-MD5, rc=%d\n", rc); goto unlock;
}
/* calculate ntlmv2_hash */
rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp, hmacmd5); if (rc) {
cifs_dbg(VFS, "Could not get NTLMv2 hash, rc=%d\n", rc); goto unlock;
}
/* calculate first part of the client response (CR1) */
rc = CalcNTLMv2_response(ses, ntlmv2_hash, hmacmd5); if (rc) {
cifs_dbg(VFS, "Could not calculate CR1, rc=%d\n", rc); goto unlock;
}
/* now calculate the session key for NTLMv2 */
rc = crypto_shash_setkey(hmacmd5->tfm, ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); if (rc) {
cifs_dbg(VFS, "%s: Could not set NTLMv2 hash as a key, rc=%d\n", __func__, rc); goto unlock;
}
rc = crypto_shash_init(hmacmd5); if (rc) {
cifs_dbg(VFS, "%s: Could not init HMAC-MD5, rc=%d\n", __func__, rc); goto unlock;
}
rc = crypto_shash_update(hmacmd5, ntlmv2->ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); if (rc) {
cifs_dbg(VFS, "%s: Could not update with response, rc=%d\n", __func__, rc); goto unlock;
}
rc = crypto_shash_final(hmacmd5, ses->auth_key.response); if (rc)
cifs_dbg(VFS, "%s: Could not generate MD5 hash, rc=%d\n", __func__, rc);
unlock:
cifs_server_unlock(ses->server);
cifs_free_hash(&hmacmd5);
setup_ntlmv2_rsp_ret:
kfree_sensitive(tiblob);
return rc;
}
int
calc_seckey(struct cifs_ses *ses)
{ unsignedchar sec_key[CIFS_SESS_KEY_SIZE]; /* a nonce */ struct arc4_ctx *ctx_arc4;
if (fips_enabled) return -ENODEV;
get_random_bytes(sec_key, CIFS_SESS_KEY_SIZE);
ctx_arc4 = kmalloc(sizeof(*ctx_arc4), GFP_KERNEL); if (!ctx_arc4) {
cifs_dbg(VFS, "Could not allocate arc4 context\n"); return -ENOMEM;
}
/* make secondary_key/nonce as session key */
memcpy(ses->auth_key.response, sec_key, CIFS_SESS_KEY_SIZE); /* and make len as that of session key only */
ses->auth_key.len = CIFS_SESS_KEY_SIZE;
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.