aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/auth_gss/gss_krb5_crypto.c
diff options
context:
space:
mode:
authorKevin Coffman <kwc@citi.umich.edu>2010-03-17 13:03:00 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2010-05-14 15:09:19 -0400
commit934a95aa1c9c6ad77838800b79c306e982437605 (patch)
tree0f7000ffce214a156737fddc127fb0af238dfcff /net/sunrpc/auth_gss/gss_krb5_crypto.c
parentde9c17eb4a912c9028f7b470eb80815144883b26 (diff)
gss_krb5: add remaining pieces to enable AES encryption support
Add the remaining pieces to enable support for Kerberos AES encryption types. Signed-off-by: Kevin Coffman <kwc@citi.umich.edu> Signed-off-by: Steve Dickson <steved@redhat.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net/sunrpc/auth_gss/gss_krb5_crypto.c')
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_crypto.c248
1 files changed, 248 insertions, 0 deletions
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index ca52ac28a537..967484a914f3 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -41,6 +41,7 @@
41#include <linux/crypto.h> 41#include <linux/crypto.h>
42#include <linux/highmem.h> 42#include <linux/highmem.h>
43#include <linux/pagemap.h> 43#include <linux/pagemap.h>
44#include <linux/random.h>
44#include <linux/sunrpc/gss_krb5.h> 45#include <linux/sunrpc/gss_krb5.h>
45#include <linux/sunrpc/xdr.h> 46#include <linux/sunrpc/xdr.h>
46 47
@@ -478,3 +479,250 @@ xdr_extend_head(struct xdr_buf *buf, unsigned int base, unsigned int shiftlen)
478 479
479 return 0; 480 return 0;
480} 481}
482
483static u32
484gss_krb5_cts_crypt(struct crypto_blkcipher *cipher, struct xdr_buf *buf,
485 u32 offset, u8 *iv, struct page **pages, int encrypt)
486{
487 u32 ret;
488 struct scatterlist sg[1];
489 struct blkcipher_desc desc = { .tfm = cipher, .info = iv };
490 u8 data[crypto_blkcipher_blocksize(cipher) * 2];
491 struct page **save_pages;
492 u32 len = buf->len - offset;
493
494 BUG_ON(len > crypto_blkcipher_blocksize(cipher) * 2);
495
496 /*
497 * For encryption, we want to read from the cleartext
498 * page cache pages, and write the encrypted data to
499 * the supplied xdr_buf pages.
500 */
501 save_pages = buf->pages;
502 if (encrypt)
503 buf->pages = pages;
504
505 ret = read_bytes_from_xdr_buf(buf, offset, data, len);
506 buf->pages = save_pages;
507 if (ret)
508 goto out;
509
510 sg_init_one(sg, data, len);
511
512 if (encrypt)
513 ret = crypto_blkcipher_encrypt_iv(&desc, sg, sg, len);
514 else
515 ret = crypto_blkcipher_decrypt_iv(&desc, sg, sg, len);
516
517 if (ret)
518 goto out;
519
520 ret = write_bytes_to_xdr_buf(buf, offset, data, len);
521
522out:
523 return ret;
524}
525
526u32
527gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset,
528 struct xdr_buf *buf, int ec, struct page **pages)
529{
530 u32 err;
531 struct xdr_netobj hmac;
532 u8 *cksumkey;
533 u8 *ecptr;
534 struct crypto_blkcipher *cipher, *aux_cipher;
535 int blocksize;
536 struct page **save_pages;
537 int nblocks, nbytes;
538 struct encryptor_desc desc;
539 u32 cbcbytes;
540
541 if (kctx->initiate) {
542 cipher = kctx->initiator_enc;
543 aux_cipher = kctx->initiator_enc_aux;
544 cksumkey = kctx->initiator_integ;
545 } else {
546 cipher = kctx->acceptor_enc;
547 aux_cipher = kctx->acceptor_enc_aux;
548 cksumkey = kctx->acceptor_integ;
549 }
550 blocksize = crypto_blkcipher_blocksize(cipher);
551
552 /* hide the gss token header and insert the confounder */
553 offset += GSS_KRB5_TOK_HDR_LEN;
554 if (xdr_extend_head(buf, offset, blocksize))
555 return GSS_S_FAILURE;
556 gss_krb5_make_confounder(buf->head[0].iov_base + offset, blocksize);
557 offset -= GSS_KRB5_TOK_HDR_LEN;
558
559 if (buf->tail[0].iov_base != NULL) {
560 ecptr = buf->tail[0].iov_base + buf->tail[0].iov_len;
561 } else {
562 buf->tail[0].iov_base = buf->head[0].iov_base
563 + buf->head[0].iov_len;
564 buf->tail[0].iov_len = 0;
565 ecptr = buf->tail[0].iov_base;
566 }
567
568 memset(ecptr, 'X', ec);
569 buf->tail[0].iov_len += ec;
570 buf->len += ec;
571
572 /* copy plaintext gss token header after filler (if any) */
573 memcpy(ecptr + ec, buf->head[0].iov_base + offset,
574 GSS_KRB5_TOK_HDR_LEN);
575 buf->tail[0].iov_len += GSS_KRB5_TOK_HDR_LEN;
576 buf->len += GSS_KRB5_TOK_HDR_LEN;
577
578 /* Do the HMAC */
579 hmac.len = GSS_KRB5_MAX_CKSUM_LEN;
580 hmac.data = buf->tail[0].iov_base + buf->tail[0].iov_len;
581
582 /*
583 * When we are called, pages points to the real page cache
584 * data -- which we can't go and encrypt! buf->pages points
585 * to scratch pages which we are going to send off to the
586 * client/server. Swap in the plaintext pages to calculate
587 * the hmac.
588 */
589 save_pages = buf->pages;
590 buf->pages = pages;
591
592 err = make_checksum_v2(kctx, NULL, 0, buf,
593 offset + GSS_KRB5_TOK_HDR_LEN, cksumkey, &hmac);
594 buf->pages = save_pages;
595 if (err)
596 return GSS_S_FAILURE;
597
598 nbytes = buf->len - offset - GSS_KRB5_TOK_HDR_LEN;
599 nblocks = (nbytes + blocksize - 1) / blocksize;
600 cbcbytes = 0;
601 if (nblocks > 2)
602 cbcbytes = (nblocks - 2) * blocksize;
603
604 memset(desc.iv, 0, sizeof(desc.iv));
605
606 if (cbcbytes) {
607 desc.pos = offset + GSS_KRB5_TOK_HDR_LEN;
608 desc.fragno = 0;
609 desc.fraglen = 0;
610 desc.pages = pages;
611 desc.outbuf = buf;
612 desc.desc.info = desc.iv;
613 desc.desc.flags = 0;
614 desc.desc.tfm = aux_cipher;
615
616 sg_init_table(desc.infrags, 4);
617 sg_init_table(desc.outfrags, 4);
618
619 err = xdr_process_buf(buf, offset + GSS_KRB5_TOK_HDR_LEN,
620 cbcbytes, encryptor, &desc);
621 if (err)
622 goto out_err;
623 }
624
625 /* Make sure IV carries forward from any CBC results. */
626 err = gss_krb5_cts_crypt(cipher, buf,
627 offset + GSS_KRB5_TOK_HDR_LEN + cbcbytes,
628 desc.iv, pages, 1);
629 if (err) {
630 err = GSS_S_FAILURE;
631 goto out_err;
632 }
633
634 /* Now update buf to account for HMAC */
635 buf->tail[0].iov_len += kctx->gk5e->cksumlength;
636 buf->len += kctx->gk5e->cksumlength;
637
638out_err:
639 if (err)
640 err = GSS_S_FAILURE;
641 return err;
642}
643
644u32
645gss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset, struct xdr_buf *buf,
646 u32 *headskip, u32 *tailskip)
647{
648 struct xdr_buf subbuf;
649 u32 ret = 0;
650 u8 *cksum_key;
651 struct crypto_blkcipher *cipher, *aux_cipher;
652 struct xdr_netobj our_hmac_obj;
653 u8 our_hmac[GSS_KRB5_MAX_CKSUM_LEN];
654 u8 pkt_hmac[GSS_KRB5_MAX_CKSUM_LEN];
655 int nblocks, blocksize, cbcbytes;
656 struct decryptor_desc desc;
657
658 if (kctx->initiate) {
659 cipher = kctx->acceptor_enc;
660 aux_cipher = kctx->acceptor_enc_aux;
661 cksum_key = kctx->acceptor_integ;
662 } else {
663 cipher = kctx->initiator_enc;
664 aux_cipher = kctx->initiator_enc_aux;
665 cksum_key = kctx->initiator_integ;
666 }
667 blocksize = crypto_blkcipher_blocksize(cipher);
668
669
670 /* create a segment skipping the header and leaving out the checksum */
671 xdr_buf_subsegment(buf, &subbuf, offset + GSS_KRB5_TOK_HDR_LEN,
672 (buf->len - offset - GSS_KRB5_TOK_HDR_LEN -
673 kctx->gk5e->cksumlength));
674
675 nblocks = (subbuf.len + blocksize - 1) / blocksize;
676
677 cbcbytes = 0;
678 if (nblocks > 2)
679 cbcbytes = (nblocks - 2) * blocksize;
680
681 memset(desc.iv, 0, sizeof(desc.iv));
682
683 if (cbcbytes) {
684 desc.fragno = 0;
685 desc.fraglen = 0;
686 desc.desc.info = desc.iv;
687 desc.desc.flags = 0;
688 desc.desc.tfm = aux_cipher;
689
690 sg_init_table(desc.frags, 4);
691
692 ret = xdr_process_buf(&subbuf, 0, cbcbytes, decryptor, &desc);
693 if (ret)
694 goto out_err;
695 }
696
697 /* Make sure IV carries forward from any CBC results. */
698 ret = gss_krb5_cts_crypt(cipher, &subbuf, cbcbytes, desc.iv, NULL, 0);
699 if (ret)
700 goto out_err;
701
702
703 /* Calculate our hmac over the plaintext data */
704 our_hmac_obj.len = sizeof(our_hmac);
705 our_hmac_obj.data = our_hmac;
706
707 ret = make_checksum_v2(kctx, NULL, 0, &subbuf, 0,
708 cksum_key, &our_hmac_obj);
709 if (ret)
710 goto out_err;
711
712 /* Get the packet's hmac value */
713 ret = read_bytes_from_xdr_buf(buf, buf->len - kctx->gk5e->cksumlength,
714 pkt_hmac, kctx->gk5e->cksumlength);
715 if (ret)
716 goto out_err;
717
718 if (memcmp(pkt_hmac, our_hmac, kctx->gk5e->cksumlength) != 0) {
719 ret = GSS_S_BAD_SIG;
720 goto out_err;
721 }
722 *headskip = crypto_blkcipher_blocksize(cipher);
723 *tailskip = kctx->gk5e->cksumlength;
724out_err:
725 if (ret && ret != GSS_S_BAD_SIG)
726 ret = GSS_S_FAILURE;
727 return ret;
728}