| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: xform_ah.c,v 1.66 2017/07/20 03:12:05 ozaki-r Exp $ */ | | 1 | /* $NetBSD: xform_ah.c,v 1.67 2017/07/20 03:17:59 ozaki-r Exp $ */ |
2 | /* $FreeBSD: src/sys/netipsec/xform_ah.c,v 1.1.4.1 2003/01/24 05:11:36 sam Exp $ */ | | 2 | /* $FreeBSD: src/sys/netipsec/xform_ah.c,v 1.1.4.1 2003/01/24 05:11:36 sam Exp $ */ |
3 | /* $OpenBSD: ip_ah.c,v 1.63 2001/06/26 06:18:58 angelos Exp $ */ | | 3 | /* $OpenBSD: ip_ah.c,v 1.63 2001/06/26 06:18:58 angelos Exp $ */ |
4 | /* | | 4 | /* |
5 | * The authors of this code are John Ioannidis (ji@tla.org), | | 5 | * The authors of this code are John Ioannidis (ji@tla.org), |
6 | * Angelos D. Keromytis (kermit@csd.uch.gr) and | | 6 | * Angelos D. Keromytis (kermit@csd.uch.gr) and |
7 | * Niels Provos (provos@physnet.uni-hamburg.de). | | 7 | * Niels Provos (provos@physnet.uni-hamburg.de). |
8 | * | | 8 | * |
9 | * The original version of this code was written by John Ioannidis | | 9 | * The original version of this code was written by John Ioannidis |
10 | * for BSD/OS in Athens, Greece, in November 1995. | | 10 | * for BSD/OS in Athens, Greece, in November 1995. |
11 | * | | 11 | * |
12 | * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, | | 12 | * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, |
13 | * by Angelos D. Keromytis. | | 13 | * by Angelos D. Keromytis. |
14 | * | | 14 | * |
| @@ -29,27 +29,27 @@ | | | @@ -29,27 +29,27 @@ |
29 | * You may use this code under the GNU public license if you so wish. Please | | 29 | * You may use this code under the GNU public license if you so wish. Please |
30 | * contribute changes back to the authors under this freer than GPL license | | 30 | * contribute changes back to the authors under this freer than GPL license |
31 | * so that we may further the use of strong encryption without limitations to | | 31 | * so that we may further the use of strong encryption without limitations to |
32 | * all. | | 32 | * all. |
33 | * | | 33 | * |
34 | * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR | | 34 | * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR |
35 | * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY | | 35 | * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY |
36 | * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE | | 36 | * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE |
37 | * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR | | 37 | * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR |
38 | * PURPOSE. | | 38 | * PURPOSE. |
39 | */ | | 39 | */ |
40 | | | 40 | |
41 | #include <sys/cdefs.h> | | 41 | #include <sys/cdefs.h> |
42 | __KERNEL_RCSID(0, "$NetBSD: xform_ah.c,v 1.66 2017/07/20 03:12:05 ozaki-r Exp $"); | | 42 | __KERNEL_RCSID(0, "$NetBSD: xform_ah.c,v 1.67 2017/07/20 03:17:59 ozaki-r Exp $"); |
43 | | | 43 | |
44 | #if defined(_KERNEL_OPT) | | 44 | #if defined(_KERNEL_OPT) |
45 | #include "opt_inet.h" | | 45 | #include "opt_inet.h" |
46 | #include "opt_ipsec.h" | | 46 | #include "opt_ipsec.h" |
47 | #endif | | 47 | #endif |
48 | | | 48 | |
49 | #include <sys/param.h> | | 49 | #include <sys/param.h> |
50 | #include <sys/systm.h> | | 50 | #include <sys/systm.h> |
51 | #include <sys/mbuf.h> | | 51 | #include <sys/mbuf.h> |
52 | #include <sys/socket.h> | | 52 | #include <sys/socket.h> |
53 | #include <sys/syslog.h> | | 53 | #include <sys/syslog.h> |
54 | #include <sys/kernel.h> | | 54 | #include <sys/kernel.h> |
55 | #include <sys/sysctl.h> | | 55 | #include <sys/sysctl.h> |
| @@ -608,166 +608,168 @@ ah_massage_headers(struct mbuf **m0, int | | | @@ -608,166 +608,168 @@ ah_massage_headers(struct mbuf **m0, int |
608 | } | | 608 | } |
609 | | | 609 | |
610 | return 0; | | 610 | return 0; |
611 | } | | 611 | } |
612 | | | 612 | |
613 | /* | | 613 | /* |
614 | * ah_input() gets called to verify that an input packet | | 614 | * ah_input() gets called to verify that an input packet |
615 | * passes authentication. | | 615 | * passes authentication. |
616 | */ | | 616 | */ |
617 | static int | | 617 | static int |
618 | ah_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff) | | 618 | ah_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff) |
619 | { | | 619 | { |
620 | const struct auth_hash *ahx; | | 620 | const struct auth_hash *ahx; |
621 | struct tdb_crypto *tc; | | 621 | struct tdb_crypto *tc = NULL; |
622 | struct newah *ah; | | 622 | struct newah *ah; |
623 | int hl, rplen, authsize, error; | | 623 | int hl, rplen, authsize, error, stat = AH_STAT_HDROPS; |
624 | | | | |
625 | struct cryptodesc *crda; | | 624 | struct cryptodesc *crda; |
626 | struct cryptop *crp; | | 625 | struct cryptop *crp = NULL; |
627 | | | 626 | |
628 | IPSEC_SPLASSERT_SOFTNET(__func__); | | 627 | IPSEC_SPLASSERT_SOFTNET(__func__); |
629 | | | 628 | |
630 | KASSERT(sav != NULL); | | 629 | KASSERT(sav != NULL); |
631 | KASSERT(sav->key_auth != NULL); | | 630 | KASSERT(sav->key_auth != NULL); |
632 | KASSERT(sav->tdb_authalgxform != NULL); | | 631 | KASSERT(sav->tdb_authalgxform != NULL); |
633 | | | 632 | |
634 | /* Figure out header size. */ | | 633 | /* Figure out header size. */ |
635 | rplen = HDRSIZE(sav); | | 634 | rplen = HDRSIZE(sav); |
636 | | | 635 | |
637 | /* XXX don't pullup, just copy header */ | | 636 | /* XXX don't pullup, just copy header */ |
638 | IP6_EXTHDR_GET(ah, struct newah *, m, skip, rplen); | | 637 | IP6_EXTHDR_GET(ah, struct newah *, m, skip, rplen); |
639 | if (ah == NULL) { | | 638 | if (ah == NULL) { |
640 | DPRINTF(("%s: cannot pullup header\n", __func__)); | | 639 | DPRINTF(("%s: cannot pullup header\n", __func__)); |
641 | AH_STATINC(AH_STAT_HDROPS); /*XXX*/ | | 640 | error = ENOBUFS; |
642 | m_freem(m); | | 641 | stat = AH_STAT_HDROPS; /*XXX*/ |
643 | return ENOBUFS; | | 642 | goto bad; |
644 | } | | 643 | } |
645 | | | 644 | |
646 | /* Check replay window, if applicable. */ | | 645 | /* Check replay window, if applicable. */ |
647 | if (sav->replay && !ipsec_chkreplay(ntohl(ah->ah_seq), sav)) { | | 646 | if (sav->replay && !ipsec_chkreplay(ntohl(ah->ah_seq), sav)) { |
648 | char buf[IPSEC_LOGSASTRLEN]; | | 647 | char buf[IPSEC_LOGSASTRLEN]; |
649 | AH_STATINC(AH_STAT_REPLAY); | | | |
650 | DPRINTF(("%s: packet replay failure: %s\n", __func__, | | 648 | DPRINTF(("%s: packet replay failure: %s\n", __func__, |
651 | ipsec_logsastr(sav, buf, sizeof(buf)))); | | 649 | ipsec_logsastr(sav, buf, sizeof(buf)))); |
652 | m_freem(m); | | 650 | stat = AH_STAT_REPLAY; |
653 | return ENOBUFS; | | 651 | error = ENOBUFS; |
| | | 652 | goto bad; |
654 | } | | 653 | } |
655 | | | 654 | |
656 | /* Verify AH header length. */ | | 655 | /* Verify AH header length. */ |
657 | hl = ah->ah_len * sizeof(uint32_t); | | 656 | hl = ah->ah_len * sizeof(uint32_t); |
658 | ahx = sav->tdb_authalgxform; | | 657 | ahx = sav->tdb_authalgxform; |
659 | authsize = AUTHSIZE(sav); | | 658 | authsize = AUTHSIZE(sav); |
660 | if (hl != authsize + rplen - sizeof(struct ah)) { | | 659 | if (hl != authsize + rplen - sizeof(struct ah)) { |
661 | char buf[IPSEC_ADDRSTRLEN]; | | 660 | char buf[IPSEC_ADDRSTRLEN]; |
662 | DPRINTF(("%s: bad authenticator length %u (expecting %lu)" | | 661 | DPRINTF(("%s: bad authenticator length %u (expecting %lu)" |
663 | " for packet in SA %s/%08lx\n", __func__, | | 662 | " for packet in SA %s/%08lx\n", __func__, |
664 | hl, (u_long) (authsize + rplen - sizeof(struct ah)), | | 663 | hl, (u_long) (authsize + rplen - sizeof(struct ah)), |
665 | ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)), | | 664 | ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)), |
666 | (u_long) ntohl(sav->spi))); | | 665 | (u_long) ntohl(sav->spi))); |
667 | AH_STATINC(AH_STAT_BADAUTHL); | | 666 | stat = AH_STAT_BADAUTHL; |
668 | m_freem(m); | | 667 | error = EACCES; |
669 | return EACCES; | | 668 | goto bad; |
670 | } | | 669 | } |
671 | AH_STATADD(AH_STAT_IBYTES, m->m_pkthdr.len - skip - hl); | | 670 | AH_STATADD(AH_STAT_IBYTES, m->m_pkthdr.len - skip - hl); |
672 | | | 671 | |
673 | /* Get crypto descriptors. */ | | 672 | /* Get crypto descriptors. */ |
674 | crp = crypto_getreq(1); | | 673 | crp = crypto_getreq(1); |
675 | if (crp == NULL) { | | 674 | if (crp == NULL) { |
676 | DPRINTF(("%s: failed to acquire crypto descriptor\n", __func__)); | | 675 | DPRINTF(("%s: failed to acquire crypto descriptor\n", __func__)); |
677 | AH_STATINC(AH_STAT_CRYPTO); | | 676 | stat = AH_STAT_CRYPTO; |
678 | m_freem(m); | | 677 | error = ENOBUFS; |
679 | return ENOBUFS; | | 678 | goto bad; |
680 | } | | 679 | } |
681 | | | 680 | |
682 | crda = crp->crp_desc; | | 681 | crda = crp->crp_desc; |
683 | KASSERT(crda != NULL); | | 682 | KASSERT(crda != NULL); |
684 | | | 683 | |
685 | crda->crd_skip = 0; | | 684 | crda->crd_skip = 0; |
686 | crda->crd_len = m->m_pkthdr.len; | | 685 | crda->crd_len = m->m_pkthdr.len; |
687 | crda->crd_inject = skip + rplen; | | 686 | crda->crd_inject = skip + rplen; |
688 | | | 687 | |
689 | /* Authentication operation. */ | | 688 | /* Authentication operation. */ |
690 | crda->crd_alg = ahx->type; | | 689 | crda->crd_alg = ahx->type; |
691 | crda->crd_key = _KEYBUF(sav->key_auth); | | 690 | crda->crd_key = _KEYBUF(sav->key_auth); |
692 | crda->crd_klen = _KEYBITS(sav->key_auth); | | 691 | crda->crd_klen = _KEYBITS(sav->key_auth); |
693 | | | 692 | |
694 | /* Allocate IPsec-specific opaque crypto info. */ | | 693 | /* Allocate IPsec-specific opaque crypto info. */ |
695 | size_t size = sizeof(*tc); | | 694 | size_t size = sizeof(*tc); |
696 | size_t extra = skip + rplen + authsize; | | 695 | size_t extra = skip + rplen + authsize; |
697 | size += extra; | | 696 | size += extra; |
698 | | | 697 | |
699 | tc = malloc(size, M_XDATA, M_NOWAIT|M_ZERO); | | 698 | tc = malloc(size, M_XDATA, M_NOWAIT|M_ZERO); |
700 | if (tc == NULL) { | | 699 | if (tc == NULL) { |
701 | DPRINTF(("%s: failed to allocate tdb_crypto\n", __func__)); | | 700 | DPRINTF(("%s: failed to allocate tdb_crypto\n", __func__)); |
702 | AH_STATINC(AH_STAT_CRYPTO); | | 701 | stat = AH_STAT_CRYPTO; |
703 | crypto_freereq(crp); | | 702 | error = ENOBUFS; |
704 | m_freem(m); | | 703 | goto bad; |
705 | return ENOBUFS; | | | |
706 | } | | 704 | } |
707 | | | 705 | |
708 | error = m_makewritable(&m, 0, extra, M_NOWAIT); | | 706 | error = m_makewritable(&m, 0, extra, M_NOWAIT); |
709 | if (error) { | | 707 | if (error) { |
710 | m_freem(m); | | | |
711 | DPRINTF(("%s: failed to m_makewritable\n", __func__)); | | 708 | DPRINTF(("%s: failed to m_makewritable\n", __func__)); |
712 | AH_STATINC(AH_STAT_HDROPS); | | 709 | goto bad; |
713 | free(tc, M_XDATA); | | | |
714 | crypto_freereq(crp); | | | |
715 | return error; | | | |
716 | } | | 710 | } |
717 | | | 711 | |
718 | /* | | 712 | /* |
719 | * Save the authenticator, the skipped portion of the packet, | | 713 | * Save the authenticator, the skipped portion of the packet, |
720 | * and the AH header. | | 714 | * and the AH header. |
721 | */ | | 715 | */ |
722 | m_copydata(m, 0, extra, (tc + 1)); | | 716 | m_copydata(m, 0, extra, (tc + 1)); |
723 | /* Zeroize the authenticator on the packet. */ | | 717 | /* Zeroize the authenticator on the packet. */ |
724 | m_copyback(m, skip + rplen, authsize, ipseczeroes); | | 718 | m_copyback(m, skip + rplen, authsize, ipseczeroes); |
725 | | | 719 | |
726 | /* "Massage" the packet headers for crypto processing. */ | | 720 | /* "Massage" the packet headers for crypto processing. */ |
727 | error = ah_massage_headers(&m, sav->sah->saidx.dst.sa.sa_family, | | 721 | error = ah_massage_headers(&m, sav->sah->saidx.dst.sa.sa_family, |
728 | skip, ahx->type, 0); | | 722 | skip, ahx->type, 0); |
729 | if (error != 0) { | | 723 | if (error != 0) { |
730 | /* NB: mbuf is free'd by ah_massage_headers */ | | 724 | /* NB: mbuf is free'd by ah_massage_headers */ |
731 | AH_STATINC(AH_STAT_HDROPS); | | 725 | m = NULL; |
732 | free(tc, M_XDATA); | | 726 | goto bad; |
733 | crypto_freereq(crp); | | | |
734 | return error; | | | |
735 | } | | 727 | } |
736 | | | 728 | |
737 | /* Crypto operation descriptor. */ | | 729 | /* Crypto operation descriptor. */ |
738 | crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */ | | 730 | crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */ |
739 | crp->crp_flags = CRYPTO_F_IMBUF; | | 731 | crp->crp_flags = CRYPTO_F_IMBUF; |
740 | crp->crp_buf = m; | | 732 | crp->crp_buf = m; |
741 | crp->crp_callback = ah_input_cb; | | 733 | crp->crp_callback = ah_input_cb; |
742 | crp->crp_sid = sav->tdb_cryptoid; | | 734 | crp->crp_sid = sav->tdb_cryptoid; |
743 | crp->crp_opaque = tc; | | 735 | crp->crp_opaque = tc; |
744 | | | 736 | |
745 | /* These are passed as-is to the callback. */ | | 737 | /* These are passed as-is to the callback. */ |
746 | tc->tc_spi = sav->spi; | | 738 | tc->tc_spi = sav->spi; |
747 | tc->tc_dst = sav->sah->saidx.dst; | | 739 | tc->tc_dst = sav->sah->saidx.dst; |
748 | tc->tc_proto = sav->sah->saidx.proto; | | 740 | tc->tc_proto = sav->sah->saidx.proto; |
749 | tc->tc_nxt = ah->ah_nxt; | | 741 | tc->tc_nxt = ah->ah_nxt; |
750 | tc->tc_protoff = protoff; | | 742 | tc->tc_protoff = protoff; |
751 | tc->tc_skip = skip; | | 743 | tc->tc_skip = skip; |
752 | tc->tc_sav = sav; | | 744 | tc->tc_sav = sav; |
753 | KEY_SA_REF(sav); | | 745 | KEY_SA_REF(sav); |
754 | | | 746 | |
755 | DPRINTF(("%s: hash over %d bytes, skip %d: " | | 747 | DPRINTF(("%s: hash over %d bytes, skip %d: " |
756 | "crda len %d skip %d inject %d\n", __func__, | | 748 | "crda len %d skip %d inject %d\n", __func__, |
757 | crp->crp_ilen, tc->tc_skip, | | 749 | crp->crp_ilen, tc->tc_skip, |
758 | crda->crd_len, crda->crd_skip, crda->crd_inject)); | | 750 | crda->crd_len, crda->crd_skip, crda->crd_inject)); |
759 | | | 751 | |
760 | return crypto_dispatch(crp); | | 752 | return crypto_dispatch(crp); |
| | | 753 | |
| | | 754 | bad: |
| | | 755 | if (tc != NULL) |
| | | 756 | free(tc, M_XDATA); |
| | | 757 | if (crp != NULL) |
| | | 758 | crypto_freereq(crp); |
| | | 759 | if (m != NULL) |
| | | 760 | m_freem(m); |
| | | 761 | AH_STATINC(stat); |
| | | 762 | return error; |
761 | } | | 763 | } |
762 | | | 764 | |
763 | #ifdef INET6 | | 765 | #ifdef INET6 |
764 | #define IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff) do { \ | | 766 | #define IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff) do { \ |
765 | if (saidx->dst.sa.sa_family == AF_INET6) { \ | | 767 | if (saidx->dst.sa.sa_family == AF_INET6) { \ |
766 | error = ipsec6_common_input_cb(m, sav, skip, protoff); \ | | 768 | error = ipsec6_common_input_cb(m, sav, skip, protoff); \ |
767 | } else { \ | | 769 | } else { \ |
768 | error = ipsec4_common_input_cb(m, sav, skip, protoff); \ | | 770 | error = ipsec4_common_input_cb(m, sav, skip, protoff); \ |
769 | } \ | | 771 | } \ |
770 | } while (0) | | 772 | } while (0) |
771 | #else | | 773 | #else |
772 | #define IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff) \ | | 774 | #define IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff) \ |
773 | (error = ipsec4_common_input_cb(m, sav, skip, protoff)) | | 775 | (error = ipsec4_common_input_cb(m, sav, skip, protoff)) |