@@ -761,6 +761,148 @@ void tcp_ao_syncookie(struct sock *sk, const struct sk_buff *skb,
761761 treq -> maclen = tcp_ao_maclen (key );
762762}
763763
764+ static enum skb_drop_reason
765+ tcp_ao_verify_hash (const struct sock * sk , const struct sk_buff * skb ,
766+ unsigned short int family , struct tcp_ao_info * info ,
767+ const struct tcp_ao_hdr * aoh , struct tcp_ao_key * key ,
768+ u8 * traffic_key , u8 * phash , u32 sne )
769+ {
770+ u8 maclen = aoh -> length - sizeof (struct tcp_ao_hdr );
771+ const struct tcphdr * th = tcp_hdr (skb );
772+ void * hash_buf = NULL ;
773+
774+ if (maclen != tcp_ao_maclen (key ))
775+ return SKB_DROP_REASON_TCP_AOFAILURE ;
776+
777+ hash_buf = kmalloc (tcp_ao_digest_size (key ), GFP_ATOMIC );
778+ if (!hash_buf )
779+ return SKB_DROP_REASON_NOT_SPECIFIED ;
780+
781+ /* XXX: make it per-AF callback? */
782+ tcp_ao_hash_skb (family , hash_buf , key , sk , skb , traffic_key ,
783+ (phash - (u8 * )th ), sne );
784+ if (memcmp (phash , hash_buf , maclen )) {
785+ kfree (hash_buf );
786+ return SKB_DROP_REASON_TCP_AOFAILURE ;
787+ }
788+ kfree (hash_buf );
789+ return SKB_NOT_DROPPED_YET ;
790+ }
791+
792+ enum skb_drop_reason
793+ tcp_inbound_ao_hash (struct sock * sk , const struct sk_buff * skb ,
794+ unsigned short int family , const struct request_sock * req ,
795+ const struct tcp_ao_hdr * aoh )
796+ {
797+ const struct tcphdr * th = tcp_hdr (skb );
798+ u8 * phash = (u8 * )(aoh + 1 ); /* hash goes just after the header */
799+ struct tcp_ao_info * info ;
800+ enum skb_drop_reason ret ;
801+ struct tcp_ao_key * key ;
802+ __be32 sisn , disn ;
803+ u8 * traffic_key ;
804+ u32 sne = 0 ;
805+
806+ info = rcu_dereference (tcp_sk (sk )-> ao_info );
807+ if (!info )
808+ return SKB_DROP_REASON_TCP_AOUNEXPECTED ;
809+
810+ if (unlikely (th -> syn )) {
811+ sisn = th -> seq ;
812+ disn = 0 ;
813+ }
814+
815+ /* Fast-path */
816+ if (likely ((1 << sk -> sk_state ) & TCP_AO_ESTABLISHED )) {
817+ enum skb_drop_reason err ;
818+ struct tcp_ao_key * current_key ;
819+
820+ /* Check if this socket's rnext_key matches the keyid in the
821+ * packet. If not we lookup the key based on the keyid
822+ * matching the rcvid in the mkt.
823+ */
824+ key = READ_ONCE (info -> rnext_key );
825+ if (key -> rcvid != aoh -> keyid ) {
826+ key = tcp_ao_established_key (info , -1 , aoh -> keyid );
827+ if (!key )
828+ goto key_not_found ;
829+ }
830+
831+ /* Delayed retransmitted SYN */
832+ if (unlikely (th -> syn && !th -> ack ))
833+ goto verify_hash ;
834+
835+ sne = 0 ;
836+ /* Established socket, traffic key are cached */
837+ traffic_key = rcv_other_key (key );
838+ err = tcp_ao_verify_hash (sk , skb , family , info , aoh , key ,
839+ traffic_key , phash , sne );
840+ if (err )
841+ return err ;
842+ current_key = READ_ONCE (info -> current_key );
843+ /* Key rotation: the peer asks us to use new key (RNext) */
844+ if (unlikely (aoh -> rnext_keyid != current_key -> sndid )) {
845+ /* If the key is not found we do nothing. */
846+ key = tcp_ao_established_key (info , aoh -> rnext_keyid , -1 );
847+ if (key )
848+ /* pairs with tcp_ao_del_cmd */
849+ WRITE_ONCE (info -> current_key , key );
850+ }
851+ return SKB_NOT_DROPPED_YET ;
852+ }
853+
854+ /* Lookup key based on peer address and keyid.
855+ * current_key and rnext_key must not be used on tcp listen
856+ * sockets as otherwise:
857+ * - request sockets would race on those key pointers
858+ * - tcp_ao_del_cmd() allows async key removal
859+ */
860+ key = tcp_ao_inbound_lookup (family , sk , skb , -1 , aoh -> keyid );
861+ if (!key )
862+ goto key_not_found ;
863+
864+ if (th -> syn && !th -> ack )
865+ goto verify_hash ;
866+
867+ if ((1 << sk -> sk_state ) & (TCPF_LISTEN | TCPF_NEW_SYN_RECV )) {
868+ /* Make the initial syn the likely case here */
869+ if (unlikely (req )) {
870+ sne = 0 ;
871+ sisn = htonl (tcp_rsk (req )-> rcv_isn );
872+ disn = htonl (tcp_rsk (req )-> snt_isn );
873+ } else if (unlikely (th -> ack && !th -> syn )) {
874+ /* Possible syncookie packet */
875+ sisn = htonl (ntohl (th -> seq ) - 1 );
876+ disn = htonl (ntohl (th -> ack_seq ) - 1 );
877+ sne = 0 ;
878+ } else if (unlikely (!th -> syn )) {
879+ /* no way to figure out initial sisn/disn - drop */
880+ return SKB_DROP_REASON_TCP_FLAGS ;
881+ }
882+ } else if ((1 << sk -> sk_state ) & (TCPF_SYN_SENT | TCPF_SYN_RECV )) {
883+ disn = info -> lisn ;
884+ if (th -> syn || th -> rst )
885+ sisn = th -> seq ;
886+ else
887+ sisn = info -> risn ;
888+ } else {
889+ WARN_ONCE (1 , "TCP-AO: Unexpected sk_state %d" , sk -> sk_state );
890+ return SKB_DROP_REASON_TCP_AOFAILURE ;
891+ }
892+ verify_hash :
893+ traffic_key = kmalloc (tcp_ao_digest_size (key ), GFP_ATOMIC );
894+ if (!traffic_key )
895+ return SKB_DROP_REASON_NOT_SPECIFIED ;
896+ tcp_ao_calc_key_skb (key , traffic_key , skb , sisn , disn , family );
897+ ret = tcp_ao_verify_hash (sk , skb , family , info , aoh , key ,
898+ traffic_key , phash , sne );
899+ kfree (traffic_key );
900+ return ret ;
901+
902+ key_not_found :
903+ return SKB_DROP_REASON_TCP_AOKEYNOTFOUND ;
904+ }
905+
764906static int tcp_ao_cache_traffic_keys (const struct sock * sk ,
765907 struct tcp_ao_info * ao ,
766908 struct tcp_ao_key * ao_key )
0 commit comments