aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/cifsencrypt.c
diff options
context:
space:
mode:
authorShirish Pargaonkar <shirishpargaonkar@gmail.com>2010-10-21 15:25:08 -0400
committerSteve French <sfrench@us.ibm.com>2010-10-26 14:35:31 -0400
commitd2b915210b5ec01409f581421d633eca6c38d444 (patch)
tree5e4467f4888eb8c9936fbfd7b5bd7b9058af26e9 /fs/cifs/cifsencrypt.c
parentb235f371a2572d7c86a121d96d889eee02ed00e2 (diff)
NTLM auth and sign - Define crypto hash functions and create and send keys needed for key exchange
Mark dependency on crypto modules in Kconfig. Defining per structures sdesc and cifs_secmech which are used to store crypto hash functions and contexts. They are stored per smb connection and used for all auth mechs to genereate hash values and signatures. Allocate crypto hashing functions, security descriptiors, and respective contexts when a smb/tcp connection is established. Release them when a tcp/smb connection is taken down. md5 and hmac-md5 are two crypto hashing functions that are used throught the life of an smb/tcp connection by various functions that calcualte signagure and ntlmv2 hash, HMAC etc. structure ntlmssp_auth is defined as per smb connection. ntlmssp_auth holds ciphertext which is genereated by rc4/arc4 encryption of secondary key, a nonce using ntlmv2 session key and sent in the session key field of the type 3 message sent by the client during ntlmssp negotiation/exchange A key is exchanged with the server if client indicates so in flags in type 1 messsage and server agrees in flag in type 2 message of ntlmssp negotiation. If both client and agree, a key sent by client in type 3 message of ntlmssp negotiation in the session key field. The key is a ciphertext generated off of secondary key, a nonce, using ntlmv2 hash via rc4/arc4. Signing works for ntlmssp in this patch. The sequence number within the server structure needs to be zero until session is established i.e. till type 3 packet of ntlmssp exchange of a to be very first smb session on that smb connection is sent. Acked-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/cifsencrypt.c')
-rw-r--r--fs/cifs/cifsencrypt.c113
1 files changed, 113 insertions, 0 deletions
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 987b479d55dd..eaa2327ee7af 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -541,6 +541,119 @@ setup_ntlmv2_rsp_ret:
541 return rc; 541 return rc;
542} 542}
543 543
544int
545calc_seckey(struct cifsSesInfo *ses)
546{
547 int rc;
548 struct crypto_blkcipher *tfm_arc4;
549 struct scatterlist sgin, sgout;
550 struct blkcipher_desc desc;
551 unsigned char sec_key[CIFS_SESS_KEY_SIZE]; /* a nonce */
552
553 get_random_bytes(sec_key, CIFS_SESS_KEY_SIZE);
554
555 tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
556 if (!tfm_arc4 || IS_ERR(tfm_arc4)) {
557 cERROR(1, "could not allocate crypto API arc4\n");
558 return PTR_ERR(tfm_arc4);
559 }
560
561 desc.tfm = tfm_arc4;
562
563 crypto_blkcipher_setkey(tfm_arc4, ses->auth_key.response,
564 CIFS_SESS_KEY_SIZE);
565
566 sg_init_one(&sgin, sec_key, CIFS_SESS_KEY_SIZE);
567 sg_init_one(&sgout, ses->ntlmssp.ciphertext, CIFS_CPHTXT_SIZE);
568
569 rc = crypto_blkcipher_encrypt(&desc, &sgout, &sgin, CIFS_CPHTXT_SIZE);
570 if (rc) {
571 cERROR(1, "could not encrypt session key rc: %d\n", rc);
572 crypto_free_blkcipher(tfm_arc4);
573 return rc;
574 }
575
576 /* make secondary_key/nonce as session key */
577 memcpy(ses->auth_key.response, sec_key, CIFS_SESS_KEY_SIZE);
578 /* and make len as that of session key only */
579 ses->auth_key.len = CIFS_SESS_KEY_SIZE;
580
581 crypto_free_blkcipher(tfm_arc4);
582
583 return 0;
584}
585
586void
587cifs_crypto_shash_release(struct TCP_Server_Info *server)
588{
589 if (server->secmech.md5)
590 crypto_free_shash(server->secmech.md5);
591
592 if (server->secmech.hmacmd5)
593 crypto_free_shash(server->secmech.hmacmd5);
594
595 kfree(server->secmech.sdeschmacmd5);
596
597 kfree(server->secmech.sdescmd5);
598}
599
600int
601cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
602{
603 int rc;
604 unsigned int size;
605
606 server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
607 if (!server->secmech.hmacmd5 ||
608 IS_ERR(server->secmech.hmacmd5)) {
609 cERROR(1, "could not allocate crypto hmacmd5\n");
610 return PTR_ERR(server->secmech.hmacmd5);
611 }
612
613 server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
614 if (!server->secmech.md5 || IS_ERR(server->secmech.md5)) {
615 cERROR(1, "could not allocate crypto md5\n");
616 rc = PTR_ERR(server->secmech.md5);
617 goto crypto_allocate_md5_fail;
618 }
619
620 size = sizeof(struct shash_desc) +
621 crypto_shash_descsize(server->secmech.hmacmd5);
622 server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
623 if (!server->secmech.sdeschmacmd5) {
624 cERROR(1, "cifs_crypto_shash_allocate: can't alloc hmacmd5\n");
625 rc = -ENOMEM;
626 goto crypto_allocate_hmacmd5_sdesc_fail;
627 }
628 server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
629 server->secmech.sdeschmacmd5->shash.flags = 0x0;
630
631
632 size = sizeof(struct shash_desc) +
633 crypto_shash_descsize(server->secmech.md5);
634 server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
635 if (!server->secmech.sdescmd5) {
636 cERROR(1, "cifs_crypto_shash_allocate: can't alloc md5\n");
637 rc = -ENOMEM;
638 goto crypto_allocate_md5_sdesc_fail;
639 }
640 server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
641 server->secmech.sdescmd5->shash.flags = 0x0;
642
643 return 0;
644
645crypto_allocate_md5_sdesc_fail:
646 kfree(server->secmech.sdeschmacmd5);
647
648crypto_allocate_hmacmd5_sdesc_fail:
649 crypto_free_shash(server->secmech.md5);
650
651crypto_allocate_md5_fail:
652 crypto_free_shash(server->secmech.hmacmd5);
653
654 return rc;
655}
656
544void CalcNTLMv2_response(const struct cifsSesInfo *ses) 657void CalcNTLMv2_response(const struct cifsSesInfo *ses)
545{ 658{
546 unsigned int offset = CIFS_SESS_KEY_SIZE + 8; 659 unsigned int offset = CIFS_SESS_KEY_SIZE + 8;