1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#ifndef _XFRM_CONTROLLER_H
17#define _XFRM_CONTROLLER_H
18
19#include <atomic>
20#include <list>
21#include <map>
22#include <string>
23#include <utility> // for pair
24
25#include <linux/netlink.h>
26#include <linux/udp.h>
27#include <linux/xfrm.h>
28#include <sysutils/SocketClient.h>
29#include <utils/RWLock.h>
30
31#include "NetdConstants.h"
32
33namespace android {
34namespace net {
35
36// Suggest we avoid the smallest and largest ints
37class XfrmMessage;
38class TransportModeSecurityAssociation;
39
40class XfrmSocket {
41public:
42    virtual void close() {
43        if (mSock >= 0) {
44            ::close(mSock);
45        }
46        mSock = -1;
47    }
48
49    virtual bool open() = 0;
50
51    virtual ~XfrmSocket() { close(); }
52
53    virtual int sendMessage(uint16_t nlMsgType, uint16_t nlMsgFlags, uint16_t nlMsgSeqNum,
54                            iovec* iov, int iovLen) const = 0;
55
56protected:
57    int mSock;
58};
59
60enum struct XfrmDirection : uint8_t {
61    IN = XFRM_POLICY_IN,
62    OUT = XFRM_POLICY_OUT,
63    FORWARD = XFRM_POLICY_FWD,
64    MASK = XFRM_POLICY_MASK,
65};
66
67enum struct XfrmMode : uint8_t {
68    TRANSPORT = XFRM_MODE_TRANSPORT,
69    TUNNEL = XFRM_MODE_TUNNEL,
70};
71
72enum struct XfrmEncapType : uint16_t {
73    NONE = 0,
74    ESPINUDP_NON_IKE = UDP_ENCAP_ESPINUDP_NON_IKE,
75    ESPINUDP = UDP_ENCAP_ESPINUDP
76};
77
78struct XfrmAlgo {
79    std::string name;
80    std::vector<uint8_t> key;
81    uint16_t truncLenBits;
82};
83
84struct XfrmEncap {
85    XfrmEncapType type;
86    uint16_t srcPort;
87    uint16_t dstPort;
88};
89
90struct XfrmSaId {
91    XfrmDirection direction;
92    xfrm_address_t dstAddr; // network order
93    xfrm_address_t srcAddr;
94    int addrFamily;  // AF_INET or AF_INET6
95    int transformId; // requestId
96    int spi;
97};
98
99struct XfrmSaInfo : XfrmSaId {
100    XfrmAlgo auth;
101    XfrmAlgo crypt;
102    int netId;
103    XfrmMode mode;
104    XfrmEncap encap;
105};
106
107class XfrmController {
108public:
109    XfrmController();
110
111    int ipSecAllocateSpi(int32_t transformId, int32_t direction, const std::string& localAddress,
112                         const std::string& remoteAddress, int32_t inSpi, int32_t* outSpi);
113
114    int ipSecAddSecurityAssociation(
115        int32_t transformId, int32_t mode, int32_t direction, const std::string& localAddress,
116        const std::string& remoteAddress, int64_t underlyingNetworkHandle, int32_t spi,
117        const std::string& authAlgo, const std::vector<uint8_t>& authKey, int32_t authTruncBits,
118        const std::string& cryptAlgo, const std::vector<uint8_t>& cryptKey, int32_t cryptTruncBits,
119        int32_t encapType, int32_t encapLocalPort, int32_t encapRemotePort);
120
121    int ipSecDeleteSecurityAssociation(int32_t transformId, int32_t direction,
122                                       const std::string& localAddress,
123                                       const std::string& remoteAddress, int32_t spi);
124
125    int ipSecApplyTransportModeTransform(const android::base::unique_fd& socket,
126                                         int32_t transformId, int32_t direction,
127                                         const std::string& localAddress,
128                                         const std::string& remoteAddress, int32_t spi);
129
130    int ipSecRemoveTransportModeTransform(const android::base::unique_fd& socket);
131
132private:
133    // prevent concurrent modification of XFRM
134    android::RWLock mLock;
135
136    static constexpr size_t MAX_ALGO_LENGTH = 128;
137
138/*
139 * Below is a redefinition of the xfrm_usersa_info struct that is part
140 * of the Linux uapi <linux/xfrm.h> to align the structures to a 64-bit
141 * boundary.
142 */
143#ifdef NETLINK_COMPAT32
144    // Shadow the kernel definition of xfrm_usersa_info with a 64-bit aligned version
145    struct xfrm_usersa_info : ::xfrm_usersa_info {
146    } __attribute__((aligned(8)));
147    // Shadow the kernel's version, using the aligned version of xfrm_usersa_info
148    struct xfrm_userspi_info {
149        struct xfrm_usersa_info info;
150        __u32 min;
151        __u32 max;
152    };
153
154    /*
155     * Anyone who encounters a failure when sending netlink messages should look here
156     * first. Hitting the static_assert() below should be a strong hint that Android
157     * IPsec will probably not work with your current settings.
158     *
159     * Again, experimentally determined, the "flags" field should be the first byte in
160     * the final word of the xfrm_usersa_info struct. The check validates the size of
161     * the padding to be 7.
162     *
163     * This padding is verified to be correct on gcc/x86_64 kernel, and clang/x86 userspace.
164     */
165    static_assert(sizeof(::xfrm_usersa_info) % 8 != 0, "struct xfrm_usersa_info has changed "
166                                                       "alignment. Please consider whether this "
167                                                       "patch is needed.");
168    static_assert(sizeof(xfrm_usersa_info) - offsetof(xfrm_usersa_info, flags) == 8,
169                  "struct xfrm_usersa_info probably misaligned with kernel struct.");
170    static_assert(sizeof(xfrm_usersa_info) % 8 == 0, "struct xfrm_usersa_info_t is not 64-bit  "
171                                                     "aligned. Please consider whether this patch "
172                                                     "is needed.");
173    static_assert(sizeof(::xfrm_userspi_info) - sizeof(::xfrm_usersa_info) ==
174                      sizeof(xfrm_userspi_info) - sizeof(xfrm_usersa_info),
175                  "struct xfrm_userspi_info has changed and does not match the kernel struct.");
176#endif
177
178    struct nlattr_algo_crypt {
179        nlattr hdr;
180        xfrm_algo crypt;
181        uint8_t key[MAX_ALGO_LENGTH];
182    };
183
184    struct nlattr_algo_auth {
185        nlattr hdr;
186        xfrm_algo_auth auth;
187        uint8_t key[MAX_ALGO_LENGTH];
188    };
189
190    struct nlattr_user_tmpl {
191        nlattr hdr;
192        xfrm_user_tmpl tmpl;
193    };
194
195    struct nlattr_encap_tmpl {
196        nlattr hdr;
197        xfrm_encap_tmpl tmpl;
198    };
199
200
201    // helper function for filling in the XfrmSaInfo structure
202    static int fillXfrmSaId(int32_t direction, const std::string& localAddress,
203                            const std::string& remoteAddress, int32_t spi, XfrmSaId* xfrmId);
204
205    // Top level functions for managing a Transport Mode Transform
206    static int addTransportModeTransform(const XfrmSaInfo& record);
207    static int removeTransportModeTransform(const XfrmSaInfo& record);
208
209    // TODO(messagerefactor): FACTOR OUT ALL MESSAGE BUILDING CODE BELOW HERE
210    // Shared between SA and SP
211    static void fillTransportModeSelector(const XfrmSaInfo& record, xfrm_selector* selector);
212
213    // Shared between Transport and Tunnel Mode
214    static int fillNlAttrXfrmAlgoEnc(const XfrmAlgo& in_algo, nlattr_algo_crypt* algo);
215    static int fillNlAttrXfrmAlgoAuth(const XfrmAlgo& in_algo, nlattr_algo_auth* algo);
216    static int fillNlAttrXfrmEncapTmpl(const XfrmSaInfo& record, nlattr_encap_tmpl* tmpl);
217
218    // Functions for Creating a Transport Mode SA
219    static int createTransportModeSecurityAssociation(const XfrmSaInfo& record,
220                                                      const XfrmSocket& sock);
221    static int fillUserSaInfo(const XfrmSaInfo& record, xfrm_usersa_info* usersa);
222
223    // Functions for deleting a Transport Mode SA
224    static int deleteSecurityAssociation(const XfrmSaId& record, const XfrmSocket& sock);
225    static int fillUserSaId(const XfrmSaId& record, xfrm_usersa_id* said);
226    static int fillUserTemplate(const XfrmSaInfo& record, xfrm_user_tmpl* tmpl);
227    static int fillTransportModeUserSpInfo(const XfrmSaInfo& record, xfrm_userpolicy_info* usersp);
228
229    static int allocateSpi(const XfrmSaInfo& record, uint32_t minSpi, uint32_t maxSpi,
230                           uint32_t* outSpi, const XfrmSocket& sock);
231
232    // END TODO(messagerefactor)
233};
234
235} // namespace net
236} // namespace android
237
238#endif /* !defined(XFRM_CONTROLLER_H) */
239