Example #1
0
static int
CalcNTLMv2_response(const struct cifsSesInfo *ses, char *ntlmv2_hash)
{
	int rc;
	unsigned int offset = CIFS_SESS_KEY_SIZE + 8;

	if (!ses->server->secmech.sdeschmacmd5) {
		cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n");
		return -1;
	}

	crypto_shash_setkey(ses->server->secmech.hmacmd5,
				ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);

	rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
	if (rc) {
		cERROR(1, "CalcNTLMv2_response: could not init hmacmd5");
		return rc;
	}

	if (ses->server->secType == RawNTLMSSP)
		memcpy(ses->auth_key.response + offset,
			ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
	else
		memcpy(ses->auth_key.response + offset,
			ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
	crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
		ses->auth_key.response + offset, ses->auth_key.len - offset);

	rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
		ses->auth_key.response + CIFS_SESS_KEY_SIZE);

	return rc;
}
static struct shash_desc *init_desc(void)
{
	int rc;
	struct shash_desc *desc;

	if (hmac_tfm == NULL) {
		hmac_tfm = crypto_alloc_shash(evm_hmac, 0, CRYPTO_ALG_ASYNC);
		if (IS_ERR(hmac_tfm)) {
			pr_err("Can not allocate %s (reason: %ld)\n",
			       evm_hmac, PTR_ERR(hmac_tfm));
			rc = PTR_ERR(hmac_tfm);
			hmac_tfm = NULL;
			return ERR_PTR(rc);
		}
	}

	desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(hmac_tfm),
			GFP_KERNEL);
	if (!desc)
		return ERR_PTR(-ENOMEM);

	desc->tfm = hmac_tfm;
	desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;

	rc = crypto_shash_setkey(hmac_tfm, evmkey, evmkey_len);
	if (rc)
		goto out;
	rc = crypto_shash_init(desc);
out:
	if (rc) {
		kfree(desc);
		return ERR_PTR(rc);
	}
	return desc;
}
Example #3
0
static struct shash_desc *init_desc(char type)
{
	long rc;
	char *algo;
	struct crypto_shash **tfm;
	struct shash_desc *desc;

	if (type == EVM_XATTR_HMAC) {
		tfm = &hmac_tfm;
		algo = evm_hmac;
	} else {
		tfm = &hash_tfm;
		algo = evm_hash;
	}

	if (*tfm == NULL) {
		mutex_lock(&mutex);
		if (*tfm)
			goto out;
		*tfm = crypto_alloc_shash(algo, 0, CRYPTO_ALG_ASYNC);
		if (IS_ERR(*tfm)) {
			rc = PTR_ERR(*tfm);
			pr_err("Can not allocate %s (reason: %ld)\n", algo, rc);
			*tfm = NULL;
			mutex_unlock(&mutex);
			return ERR_PTR(rc);
		}
		if (type == EVM_XATTR_HMAC) {
			rc = crypto_shash_setkey(*tfm, evmkey, evmkey_len);
			if (rc) {
				crypto_free_shash(*tfm);
				*tfm = NULL;
				mutex_unlock(&mutex);
				return ERR_PTR(rc);
			}
		}
out:
		mutex_unlock(&mutex);
	}

	desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(*tfm),
			GFP_KERNEL);
	if (!desc)
		return ERR_PTR(-ENOMEM);

	desc->tfm = *tfm;
	desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;

	rc = crypto_shash_init(desc);
	if (rc) {
		kfree(desc);
		return ERR_PTR(rc);
	}
	return desc;
}
Example #4
0
static int p8_ghash_setkey(struct crypto_shash *tfm, const u8 *key,
    unsigned int keylen)
{
    struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(tfm));

    if (keylen != GHASH_KEY_LEN)
        return -EINVAL;

    pagefault_disable();
    enable_kernel_altivec();
    enable_kernel_fp();
    gcm_init_p8(ctx->htable, (const u64 *) key);
    pagefault_enable();
    return crypto_shash_setkey(ctx->fallback, key, keylen);
}
Example #5
0
static int
CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
{
	int rc;
	unsigned int offset = CIFS_SESS_KEY_SIZE + 8;

	if (!ses->server->secmech.sdeschmacmd5) {
		cifs_dbg(VFS, "%s: can't generate ntlmv2 hash\n", __func__);
		return -1;
	}

	rc = crypto_shash_setkey(ses->server->secmech.hmacmd5,
				ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not set NTLMV2 Hash as a key\n",
			 __func__);
		return rc;
	}

	rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
	if (rc) {
		cifs_dbg(VFS, "%s: could not init hmacmd5\n", __func__);
		return rc;
	}

	if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED)
		memcpy(ses->auth_key.response + offset,
			ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
	else
		memcpy(ses->auth_key.response + offset,
			ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
	rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
		ses->auth_key.response + offset, ses->auth_key.len - offset);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
		return rc;
	}

	rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
		ses->auth_key.response + CIFS_SESS_KEY_SIZE);
	if (rc)
		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);

	return rc;
}
Example #6
0
int orinoco_mic(struct crypto_shash *tfm_michael, u8 *key,
		u8 *da, u8 *sa, u8 priority,
		u8 *data, size_t data_len, u8 *mic)
{
	SHASH_DESC_ON_STACK(desc, tfm_michael);
	u8 hdr[ETH_HLEN + 2]; /* size of header + padding */
	int err;

	if (tfm_michael == NULL) {
		printk(KERN_WARNING "orinoco_mic: tfm_michael == NULL\n");
		return -1;
	}

	/* Copy header into buffer. We need the padding on the end zeroed */
	memcpy(&hdr[0], da, ETH_ALEN);
	memcpy(&hdr[ETH_ALEN], sa, ETH_ALEN);
	hdr[ETH_ALEN * 2] = priority;
	hdr[ETH_ALEN * 2 + 1] = 0;
	hdr[ETH_ALEN * 2 + 2] = 0;
	hdr[ETH_ALEN * 2 + 3] = 0;

	desc->tfm = tfm_michael;
	desc->flags = 0;

	err = crypto_shash_setkey(tfm_michael, key, MIC_KEYLEN);
	if (err)
		return err;

	err = crypto_shash_init(desc);
	if (err)
		return err;

	err = crypto_shash_update(desc, hdr, sizeof(hdr));
	if (err)
		return err;

	err = crypto_shash_update(desc, data, data_len);
	if (err)
		return err;

	err = crypto_shash_final(desc, mic);
	shash_desc_zero(desc);

	return err;
}
Example #7
0
static int calc_hmac(u8 *digest, const u8 *key, unsigned int keylen,
		     const u8 *buf, unsigned int buflen)
{
	struct sdesc *sdesc;
	int ret;

	sdesc = alloc_sdesc(hmacalg);
	if (IS_ERR(sdesc)) {
		pr_info("encrypted_key: can't alloc %s\n", hmac_alg);
		return PTR_ERR(sdesc);
	}

	ret = crypto_shash_setkey(hmacalg, key, keylen);
	if (!ret)
		ret = crypto_shash_digest(&sdesc->shash, buf, buflen, digest);
	kfree(sdesc);
	return ret;
}
Example #8
0
static int TSS_rawhmac(unsigned char *digest, const unsigned char *key,
		       unsigned int keylen, ...)
{
	struct sdesc *sdesc;
	va_list argp;
	unsigned int dlen;
	unsigned char *data;
	int ret;

	sdesc = init_sdesc(hmacalg);
	if (IS_ERR(sdesc)) {
		pr_info("trusted_key: can't alloc %s\n", hmac_alg);
		return PTR_ERR(sdesc);
	}

	ret = crypto_shash_setkey(hmacalg, key, keylen);
	if (ret < 0)
		goto out;
	ret = crypto_shash_init(&sdesc->shash);
	if (ret < 0)
		goto out;

	va_start(argp, keylen);
	for (;;) {
		dlen = va_arg(argp, unsigned int);
		if (dlen == 0)
			break;
		data = va_arg(argp, unsigned char *);
		if (data == NULL) {
			ret = -EINVAL;
			break;
		}
		ret = crypto_shash_update(&sdesc->shash, data, dlen);
		if (ret < 0)
			break;
	}
	va_end(argp);
	if (!ret)
		ret = crypto_shash_final(&sdesc->shash, digest);
out:
	kfree(sdesc);
	return ret;
}
Example #9
0
int
setup_ntlmv2_rsp(struct cifsSesInfo *ses, const struct nls_table *nls_cp)
{
	int rc;
	int baselen;
	unsigned int tilen;
	struct ntlmv2_resp *buf;
	char ntlmv2_hash[16];
	unsigned char *tiblob = NULL; /* target info blob */

	if (ses->server->secType == RawNTLMSSP) {
		if (!ses->domainName) {
			rc = find_domain_name(ses, nls_cp);
			if (rc) {
				cERROR(1, "error %d finding domain name", rc);
				goto setup_ntlmv2_rsp_ret;
			}
		}
	} else {
		rc = build_avpair_blob(ses, nls_cp);
		if (rc) {
			cERROR(1, "error %d building av pair blob", rc);
			goto setup_ntlmv2_rsp_ret;
		}
	}

	baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp);
	tilen = ses->auth_key.len;
	tiblob = ses->auth_key.response;

	ses->auth_key.response = kmalloc(baselen + tilen, GFP_KERNEL);
	if (!ses->auth_key.response) {
		rc = ENOMEM;
		ses->auth_key.len = 0;
		cERROR(1, "%s: Can't allocate auth blob", __func__);
		goto setup_ntlmv2_rsp_ret;
	}
	ses->auth_key.len += baselen;

	buf = (struct ntlmv2_resp *)
			(ses->auth_key.response + CIFS_SESS_KEY_SIZE);
	buf->blob_signature = cpu_to_le32(0x00000101);
	buf->reserved = 0;
	buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
	get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
	buf->reserved2 = 0;

	memcpy(ses->auth_key.response + baselen, tiblob, tilen);

	/* calculate ntlmv2_hash */
	rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp);
	if (rc) {
		cERROR(1, "could not get v2 hash rc %d", rc);
		goto setup_ntlmv2_rsp_ret;
	}

	/* calculate first part of the client response (CR1) */
	rc = CalcNTLMv2_response(ses, ntlmv2_hash);
	if (rc) {
		cERROR(1, "Could not calculate CR1  rc: %d", rc);
		goto setup_ntlmv2_rsp_ret;
	}

	/* now calculate the session key for NTLMv2 */
	crypto_shash_setkey(ses->server->secmech.hmacmd5,
		ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);

	rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
	if (rc) {
		cERROR(1, "%s: Could not init hmacmd5\n", __func__);
		goto setup_ntlmv2_rsp_ret;
	}

	crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
		ses->auth_key.response + CIFS_SESS_KEY_SIZE,
		CIFS_HMAC_MD5_HASH_SIZE);

	rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
		ses->auth_key.response);

setup_ntlmv2_rsp_ret:
	kfree(tiblob);

	return rc;
}
Example #10
0
static int calc_ntlmv2_hash(struct cifsSesInfo *ses, char *ntlmv2_hash,
			    const struct nls_table *nls_cp)
{
	int rc = 0;
	int len;
	char nt_hash[CIFS_NTHASH_SIZE];
	wchar_t *user;
	wchar_t *domain;
	wchar_t *server;

	if (!ses->server->secmech.sdeschmacmd5) {
		cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n");
		return -1;
	}

	/* calculate md4 hash of password */
	E_md4hash(ses->password, nt_hash);

	crypto_shash_setkey(ses->server->secmech.hmacmd5, nt_hash,
				CIFS_NTHASH_SIZE);

	rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
	if (rc) {
		cERROR(1, "calc_ntlmv2_hash: could not init hmacmd5\n");
		return rc;
	}

	/* convert ses->userName to unicode and uppercase */
	len = strlen(ses->userName);
	user = kmalloc(2 + (len * 2), GFP_KERNEL);
	if (user == NULL) {
		cERROR(1, "calc_ntlmv2_hash: user mem alloc failure\n");
		rc = -ENOMEM;
		goto calc_exit_2;
	}
	len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp);
	UniStrupr(user);

	crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
				(char *)user, 2 * len);

	/* convert ses->domainName to unicode and uppercase */
	if (ses->domainName) {
		len = strlen(ses->domainName);

		domain = kmalloc(2 + (len * 2), GFP_KERNEL);
		if (domain == NULL) {
			cERROR(1, "calc_ntlmv2_hash: domain mem alloc failure");
			rc = -ENOMEM;
			goto calc_exit_1;
		}
		len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len,
					nls_cp);
		crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
					(char *)domain, 2 * len);
		kfree(domain);
	} else if (ses->serverName) {
		len = strlen(ses->serverName);

		server = kmalloc(2 + (len * 2), GFP_KERNEL);
		if (server == NULL) {
			cERROR(1, "calc_ntlmv2_hash: server mem alloc failure");
			rc = -ENOMEM;
			goto calc_exit_1;
		}
		len = cifs_strtoUCS((__le16 *)server, ses->serverName, len,
					nls_cp);
		crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
					(char *)server, 2 * len);
		kfree(server);
	}

	rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
					ntlmv2_hash);

calc_exit_1:
	kfree(user);
calc_exit_2:
	return rc;
}
int
smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
{
	int i, rc;
	unsigned char smb3_signature[SMB2_CMACAES_SIZE];
	unsigned char *sigptr = smb3_signature;
	struct kvec *iov = rqst->rq_iov;
	int n_vec = rqst->rq_nvec;
	struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;

	memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE);
	memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);

	rc = crypto_shash_setkey(server->secmech.cmacaes,
		server->smb3signingkey, SMB2_CMACAES_SIZE);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__);
		return rc;
	}

	/*
	 * we already allocate sdesccmacaes 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(&server->secmech.sdesccmacaes->shash);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__);
		return rc;
	}

	for (i = 0; i < n_vec; i++) {
		if (iov[i].iov_len == 0)
			continue;
		if (iov[i].iov_base == NULL) {
			cifs_dbg(VFS, "null iovec entry");
			return -EIO;
		}
		/*
		 * The first entry includes a length field (which does not get
		 * signed that occupies the first 4 bytes before the header).
		 */
		if (i == 0) {
			if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
				break; /* nothing to sign or corrupt header */
			rc =
			crypto_shash_update(
				&server->secmech.sdesccmacaes->shash,
				iov[i].iov_base + 4, iov[i].iov_len - 4);
		} else {
			rc =
			crypto_shash_update(
				&server->secmech.sdesccmacaes->shash,
				iov[i].iov_base, iov[i].iov_len);
		}
		if (rc) {
			cifs_dbg(VFS, "%s: Couldn't update cmac aes with payload\n",
							__func__);
			return rc;
		}
	}

	/* now hash over the rq_pages array */
	for (i = 0; i < rqst->rq_npages; i++) {
		struct kvec p_iov;

		cifs_rqst_page_to_kvec(rqst, i, &p_iov);
		crypto_shash_update(&server->secmech.sdesccmacaes->shash,
					p_iov.iov_base, p_iov.iov_len);
		kunmap(rqst->rq_pages[i]);
	}

	rc = crypto_shash_final(&server->secmech.sdesccmacaes->shash,
						sigptr);
	if (rc)
		cifs_dbg(VFS, "%s: Could not generate cmac aes\n", __func__);

	memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE);

	return rc;
}
void
generate_smb3signingkey(struct TCP_Server_Info *server)
{
	unsigned char zero = 0x0;
	__u8 i[4] = {0, 0, 0, 1};
	__u8 L[4] = {0, 0, 0, 128};
	int rc = 0;
	unsigned char prfhash[SMB2_HMACSHA256_SIZE];
	unsigned char *hashptr = prfhash;

	memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE);
	memset(server->smb3signingkey, 0x0, SMB3_SIGNKEY_SIZE);

	rc = smb3_crypto_shash_allocate(server);
	if (rc) {
		cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__);
		goto smb3signkey_ret;
	}

	rc = crypto_shash_setkey(server->secmech.hmacsha256,
		server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not set with session key\n", __func__);
		goto smb3signkey_ret;
	}

	rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not init sign hmac\n", __func__);
		goto smb3signkey_ret;
	}

	rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
				i, 4);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not update with n\n", __func__);
		goto smb3signkey_ret;
	}

	rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
				"SMB2AESCMAC", 12);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not update with label\n", __func__);
		goto smb3signkey_ret;
	}

	rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
				&zero, 1);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not update with zero\n", __func__);
		goto smb3signkey_ret;
	}

	rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
				"SmbSign", 8);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not update with context\n", __func__);
		goto smb3signkey_ret;
	}

	rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
				L, 4);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not update with L\n", __func__);
		goto smb3signkey_ret;
	}

	rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash,
				hashptr);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__);
		goto smb3signkey_ret;
	}

	memcpy(server->smb3signingkey, hashptr, SMB3_SIGNKEY_SIZE);

smb3signkey_ret:
	return;
}
int
smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
{
	int i, rc;
	unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
	unsigned char *sigptr = smb2_signature;
	struct kvec *iov = rqst->rq_iov;
	int n_vec = rqst->rq_nvec;
	struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;

	memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
	memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);

	rc = smb2_crypto_shash_allocate(server);
	if (rc) {
		cifs_dbg(VFS, "%s: shah256 alloc failed\n", __func__);
		return rc;
	}

	rc = crypto_shash_setkey(server->secmech.hmacsha256,
		server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
		return rc;
	}

	rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not init sha256", __func__);
		return rc;
	}

	for (i = 0; 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;
		}
		/*
		 * The first entry includes a length field (which does not get
		 * signed that occupies the first 4 bytes before the header).
		 */
		if (i == 0) {
			if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
				break; /* nothing to sign or corrupt header */
			rc =
			crypto_shash_update(
				&server->secmech.sdeschmacsha256->shash,
				iov[i].iov_base + 4, iov[i].iov_len - 4);
		} else {
			rc =
			crypto_shash_update(
				&server->secmech.sdeschmacsha256->shash,
				iov[i].iov_base, iov[i].iov_len);
		}
		if (rc) {
			cifs_dbg(VFS, "%s: Could not update with payload\n",
				 __func__);
			return rc;
		}
	}

	/* now hash over the rq_pages array */
	for (i = 0; i < rqst->rq_npages; i++) {
		struct kvec p_iov;

		cifs_rqst_page_to_kvec(rqst, i, &p_iov);
		crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
					p_iov.iov_base, p_iov.iov_len);
		kunmap(rqst->rq_pages[i]);
	}

	rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash,
				sigptr);
	if (rc)
		cifs_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__);

	memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE);

	return rc;
}
Example #14
0
static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
			    const struct nls_table *nls_cp)
{
	int rc = 0;
	int len;
	char nt_hash[CIFS_NTHASH_SIZE];
	__le16 *user;
	wchar_t *domain;
	wchar_t *server;

	if (!ses->server->secmech.sdeschmacmd5) {
		cifs_dbg(VFS, "%s: can't generate ntlmv2 hash\n", __func__);
		return -1;
	}

	/* calculate md4 hash of password */
	E_md4hash(ses->password, nt_hash, nls_cp);

	rc = crypto_shash_setkey(ses->server->secmech.hmacmd5, nt_hash,
				CIFS_NTHASH_SIZE);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not set NT Hash as a key\n", __func__);
		return rc;
	}

	rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
	if (rc) {
		cifs_dbg(VFS, "%s: could not init hmacmd5\n", __func__);
		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) {
		rc = -ENOMEM;
		return rc;
	}

	if (len) {
		len = cifs_strtoUTF16(user, ses->user_name, len, nls_cp);
		UniStrupr(user);
	} else {
		memset(user, '\0', 2);
	}

	rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
				(char *)user, 2 * len);
	kfree(user);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not update with user\n", __func__);
		return rc;
	}

	/* convert ses->domainName to unicode and uppercase */
	if (ses->domainName) {
		len = strlen(ses->domainName);

		domain = kmalloc(2 + (len * 2), GFP_KERNEL);
		if (domain == NULL) {
			rc = -ENOMEM;
			return rc;
		}
		len = cifs_strtoUTF16((__le16 *)domain, ses->domainName, len,
				      nls_cp);
		rc =
		crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
					(char *)domain, 2 * len);
		kfree(domain);
		if (rc) {
			cifs_dbg(VFS, "%s: Could not update with domain\n",
				 __func__);
			return rc;
		}
	} else if (ses->serverName) {
		len = strlen(ses->serverName);

		server = kmalloc(2 + (len * 2), GFP_KERNEL);
		if (server == NULL) {
			rc = -ENOMEM;
			return rc;
		}
		len = cifs_strtoUTF16((__le16 *)server, ses->serverName, len,
					nls_cp);
		rc =
		crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
					(char *)server, 2 * len);
		kfree(server);
		if (rc) {
			cifs_dbg(VFS, "%s: Could not update with server\n",
				 __func__);
			return rc;
		}
	}

	rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
					ntlmv2_hash);
	if (rc)
		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);

	return rc;
}
Example #15
0
File: domain.c Project: Lyude/linux
/**
 * tb_domain_challenge_switch_key() - Challenge and approve switch
 * @tb: Domain the switch belongs to
 * @sw: Switch to approve
 *
 * For switches that support secure connect, this function generates
 * random challenge and sends it to the switch. The switch responds to
 * this and if the response matches our random challenge, the switch is
 * approved and connected.
 *
 * Return: %0 on success and negative errno in case of failure.
 */
int tb_domain_challenge_switch_key(struct tb *tb, struct tb_switch *sw)
{
	u8 challenge[TB_SWITCH_KEY_SIZE];
	u8 response[TB_SWITCH_KEY_SIZE];
	u8 hmac[TB_SWITCH_KEY_SIZE];
	struct tb_switch *parent_sw;
	struct crypto_shash *tfm;
	struct shash_desc *shash;
	int ret;

	if (!tb->cm_ops->approve_switch || !tb->cm_ops->challenge_switch_key)
		return -EPERM;

	/* The parent switch must be authorized before this one */
	parent_sw = tb_to_switch(sw->dev.parent);
	if (!parent_sw || !parent_sw->authorized)
		return -EINVAL;

	get_random_bytes(challenge, sizeof(challenge));
	ret = tb->cm_ops->challenge_switch_key(tb, sw, challenge, response);
	if (ret)
		return ret;

	tfm = crypto_alloc_shash("hmac(sha256)", 0, 0);
	if (IS_ERR(tfm))
		return PTR_ERR(tfm);

	ret = crypto_shash_setkey(tfm, sw->key, TB_SWITCH_KEY_SIZE);
	if (ret)
		goto err_free_tfm;

	shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(tfm),
			GFP_KERNEL);
	if (!shash) {
		ret = -ENOMEM;
		goto err_free_tfm;
	}

	shash->tfm = tfm;
	shash->flags = CRYPTO_TFM_REQ_MAY_SLEEP;

	memset(hmac, 0, sizeof(hmac));
	ret = crypto_shash_digest(shash, challenge, sizeof(hmac), hmac);
	if (ret)
		goto err_free_shash;

	/* The returned HMAC must match the one we calculated */
	if (memcmp(response, hmac, sizeof(hmac))) {
		ret = -EKEYREJECTED;
		goto err_free_shash;
	}

	crypto_free_shash(tfm);
	kfree(shash);

	return tb->cm_ops->approve_switch(tb, sw);

err_free_shash:
	kfree(shash);
err_free_tfm:
	crypto_free_shash(tfm);

	return ret;
}