• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 
17 package com.googlecode.android_scripting.facade.net;
18 
19 import android.app.Service;
20 import android.content.Context;
21 import android.net.IpSecAlgorithm;
22 import android.net.IpSecManager;
23 import android.net.IpSecManager.ResourceUnavailableException;
24 import android.net.IpSecManager.SecurityParameterIndex;
25 import android.net.IpSecManager.SpiUnavailableException;
26 import android.net.IpSecManager.UdpEncapsulationSocket;
27 import android.net.IpSecTransform;
28 import android.net.IpSecTransform.Builder;
29 import android.net.NetworkUtils;
30 
31 import com.google.common.io.BaseEncoding;
32 import com.googlecode.android_scripting.Log;
33 import com.googlecode.android_scripting.facade.FacadeManager;
34 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
35 import com.googlecode.android_scripting.rpc.Rpc;
36 import com.googlecode.android_scripting.rpc.RpcOptional;
37 import com.googlecode.android_scripting.rpc.RpcParameter;
38 
39 import java.io.FileDescriptor;
40 import java.io.IOException;
41 import java.net.DatagramSocket;
42 import java.net.InetAddress;
43 import java.net.Socket;
44 import java.util.HashMap;
45 
46 /*
47  * Access IpSecManager functions.
48  */
49 public class IpSecManagerFacade extends RpcReceiver {
50 
51     private final IpSecManager mIpSecManager;
52     private final Service mService;
53     private final Context mContext;
54     private static HashMap<String, SecurityParameterIndex> sSpiHashMap =
55             new HashMap<String, SecurityParameterIndex>();
56     private static HashMap<String, IpSecTransform> sTransformHashMap =
57             new HashMap<String, IpSecTransform>();
58     private static HashMap<String, UdpEncapsulationSocket> sUdpEncapHashMap =
59             new HashMap<String, UdpEncapsulationSocket>();
60 
IpSecManagerFacade(FacadeManager manager)61     public IpSecManagerFacade(FacadeManager manager) {
62         super(manager);
63         mService = manager.getService();
64         mContext = mService.getBaseContext();
65         mIpSecManager = (IpSecManager) mService.getSystemService(Context.IPSEC_SERVICE);
66     }
67 
createTransportModeTransform( String encAlgo, byte[] cryptKey, String authAlgo, byte[] authKey, Integer truncBits, SecurityParameterIndex spi, InetAddress addr, UdpEncapsulationSocket udpEncapSocket)68     private IpSecTransform createTransportModeTransform(
69             String encAlgo,
70             byte[] cryptKey,
71             String authAlgo,
72             byte[] authKey,
73             Integer truncBits,
74             SecurityParameterIndex spi,
75             InetAddress addr,
76             UdpEncapsulationSocket udpEncapSocket) {
77         Builder builder = new Builder(mContext);
78         builder = builder.setEncryption(new IpSecAlgorithm(encAlgo, cryptKey));
79         builder =
80                 builder.setAuthentication(
81                         new IpSecAlgorithm(authAlgo, authKey, truncBits.intValue()));
82         if (udpEncapSocket != null) {
83             builder = builder.setIpv4Encapsulation(udpEncapSocket, udpEncapSocket.getPort());
84         }
85         try {
86             return builder.buildTransportModeTransform(addr, spi);
87         } catch (SpiUnavailableException | IOException | ResourceUnavailableException e) {
88             Log.e("IpSec: Cannot create Transport mode transform" + e.toString());
89         }
90         return null;
91     }
92 
allocateSpi(InetAddress inetAddr)93     private SecurityParameterIndex allocateSpi(InetAddress inetAddr) {
94         try {
95             return mIpSecManager.allocateSecurityParameterIndex(inetAddr);
96         } catch (ResourceUnavailableException e) {
97             Log.e("IpSec: Reserve SPI failure " + e.toString());
98         }
99         return null;
100     }
101 
allocateSpi(InetAddress inetAddr, int requestedSpi)102     private SecurityParameterIndex allocateSpi(InetAddress inetAddr, int requestedSpi) {
103         try {
104             return mIpSecManager.allocateSecurityParameterIndex(inetAddr, requestedSpi);
105         } catch (SpiUnavailableException | ResourceUnavailableException e) {
106             Log.e("IpSec: Reserve SPI failure " + e.toString());
107         }
108         return null;
109     }
110 
openUdpEncapSocket()111     private UdpEncapsulationSocket openUdpEncapSocket() {
112         UdpEncapsulationSocket udpEncapSocket = null;
113         try {
114             return mIpSecManager.openUdpEncapsulationSocket();
115         } catch (ResourceUnavailableException | IOException e) {
116             Log.e("IpSec: Failed to open udp encap socket " + e.toString());
117         }
118         return null;
119     }
120 
openUdpEncapSocket(int port)121     private UdpEncapsulationSocket openUdpEncapSocket(int port) {
122         try {
123             return mIpSecManager.openUdpEncapsulationSocket(port);
124         } catch (ResourceUnavailableException | IOException e) {
125             Log.e("IpSec: Failed to open udp encap socket " + e.toString());
126         }
127         return null;
128     }
129 
getSpiId(SecurityParameterIndex spi)130     private String getSpiId(SecurityParameterIndex spi) {
131         return "SPI:" + spi.hashCode();
132     }
133 
getTransformId(IpSecTransform transform)134     private String getTransformId(IpSecTransform transform) {
135         return "TRANSFORM:" + transform.hashCode();
136     }
137 
getUdpEncapSockId(UdpEncapsulationSocket socket)138     private String getUdpEncapSockId(UdpEncapsulationSocket socket) {
139         return "UDPENCAPSOCK:" + socket.hashCode();
140     }
141 
142     /**
143      * Apply transport mode transform to FileDescriptor
144      * @param socketFd : Hash key of FileDescriptor object
145      * @param direction : In or Out direction to apply transform to
146      * @param id : Hash key of the transform
147      * @return True if transform is applied successfully
148      */
149     @Rpc(description = "Apply transport mode transform to FileDescriptor", returns = "True/False")
ipSecApplyTransportModeTransformFileDescriptor( String socketFd, Integer direction, String id)150     public Boolean ipSecApplyTransportModeTransformFileDescriptor(
151             String socketFd,
152             Integer direction,
153             String id) {
154         if (socketFd == null) {
155             Log.e("IpSec: Received null FileDescriptor key");
156             return false;
157         }
158         FileDescriptor fd = SocketFacade.getFileDescriptor(socketFd);
159         IpSecTransform transform = sTransformHashMap.get(id);
160         if (transform == null) {
161             Log.e("IpSec: Transform does not exist for the requested id");
162             return false;
163         }
164         try {
165             mIpSecManager.applyTransportModeTransform(fd, direction.intValue(), transform);
166         } catch (IOException e) {
167             Log.e("IpSec: Cannot apply transform to socket " + e.toString());
168             return false;
169         }
170         return true;
171     }
172 
173     /**
174      * Remove transport mode transform from a FileDescriptor
175      * @param socketFd : Hash key of FileDescriptor object
176      * @returns True if transform is removed successfully
177      */
178     @Rpc(description = "Remove transport mode transform to FileDescriptor", returns = "True/False")
ipSecRemoveTransportModeTransformsFileDescriptor(String socketFd)179     public Boolean ipSecRemoveTransportModeTransformsFileDescriptor(String socketFd) {
180         if (socketFd == null) {
181             Log.e("IpSec: Received null FileDescriptor key");
182             return false;
183         }
184         FileDescriptor fd = SocketFacade.getFileDescriptor(socketFd);
185         try {
186             mIpSecManager.removeTransportModeTransforms(fd);
187             return true;
188         } catch (IOException e) {
189             Log.e("IpSec: Failed to remove transform " + e.toString());
190         }
191         return false;
192     }
193 
194     /**
195      * Apply transport mode transform to DatagramSocket
196      * @param socketId : Hash key of DatagramSocket
197      * @param direction : In or Out direction to apply transform to
198      * @param transformId : Hash key of Transform to apply
199      * @return True if transform is applied successfully
200      */
201     @Rpc(description = "Apply transport mode transform to DatagramSocket", returns = "True/False")
ipSecApplyTransportModeTransformDatagramSocket( String socketId, Integer direction, String transformId)202     public Boolean ipSecApplyTransportModeTransformDatagramSocket(
203             String socketId,
204             Integer direction,
205             String transformId) {
206         if (socketId == null) {
207             Log.e("IpSec: Received null DatagramSocket key");
208             return false;
209         }
210         DatagramSocket socket = SocketFacade.getDatagramSocket(socketId);
211         IpSecTransform transform = sTransformHashMap.get(transformId);
212         if (transform == null) {
213             Log.e("IpSec: Transform does not exist for the requested id");
214             return false;
215         }
216         try {
217             mIpSecManager.applyTransportModeTransform(socket, direction.intValue(), transform);
218         } catch (IOException e) {
219             Log.e("IpSec: Cannot apply transform to socket " + e.toString());
220             return false;
221         }
222         return true;
223     }
224 
225     /**
226      * Remove transport mode transform from DatagramSocket
227      * @param socketId : Hash key of DatagramSocket
228      * @return True if removing transform is successful
229      */
230     @Rpc(description = "Remove transport mode tranform from DatagramSocket", returns = "True/False")
ipSecRemoveTransportModeTransformsDatagramSocket(String socketId)231     public Boolean ipSecRemoveTransportModeTransformsDatagramSocket(String socketId) {
232         if (socketId == null) {
233             Log.e("IpSec: Received null DatagramSocket key");
234             return false;
235         }
236         DatagramSocket socket = SocketFacade.getDatagramSocket(socketId);
237         try {
238             mIpSecManager.removeTransportModeTransforms(socket);
239             return true;
240         } catch (IOException e) {
241             Log.e("IpSec: Failed to remove transform " + e.toString());
242         }
243         return false;
244     }
245 
246     /**
247      * Apply transport mode transform to DatagramSocket
248      * @param socketId : Hash key of Socket
249      * @param direction : In or Out direction to apply transform to
250      * @param transformId : Hash key of Transform to apply
251      * @return True if transform is applied successfully
252      */
253     @Rpc(description = "Apply transport mode transform to Socket", returns = "True/False")
ipSecApplyTransportModeTransformSocket( String socketId, Integer direction, String transformId)254     public Boolean ipSecApplyTransportModeTransformSocket(
255             String socketId,
256             Integer direction,
257             String transformId) {
258         if (socketId == null) {
259             Log.e("IpSec: Received null Socket key");
260             return false;
261         }
262         Socket socket = SocketFacade.getSocket(socketId);
263         IpSecTransform transform = sTransformHashMap.get(transformId);
264         if (transform == null) {
265             Log.e("IpSec: Transform does not exist for the requested id");
266             return false;
267         }
268         try {
269             mIpSecManager.applyTransportModeTransform(socket, direction.intValue(), transform);
270         } catch (IOException e) {
271             Log.e("IpSec: Cannot apply transform to socket " + e.toString());
272             return false;
273         }
274         return true;
275     }
276 
277     /**
278      * Remove transport mode transform from Socket
279      * @param socketId : Hash key of DatagramSocket
280      * @return True if removing transform is successful
281      */
282     @Rpc(description = "Remove transport mode tranform from Socket", returns = "True/False")
ipSecRemoveTransportModeTransformsSocket(String socketId)283     public Boolean ipSecRemoveTransportModeTransformsSocket(String socketId) {
284         if (socketId == null) {
285             Log.e("IpSec: Received null Socket key");
286             return false;
287         }
288         Socket socket = SocketFacade.getSocket(socketId);
289         try {
290             mIpSecManager.removeTransportModeTransforms(socket);
291             return true;
292         } catch (IOException e) {
293             Log.e("IpSec: Failed to remove transform " + e.toString());
294         }
295         return false;
296     }
297 
298     @Rpc(description = "Create a transform mode transform", returns = "Hash of transform object")
ipSecCreateTransportModeTransform( String encAlgo, String cryptKeyHex, String authAlgo, String authKeyHex, Integer truncBits, String spiId, String addr, String udpEncapSockId)299     public String ipSecCreateTransportModeTransform(
300             String encAlgo,
301             String cryptKeyHex,
302             String authAlgo,
303             String authKeyHex,
304             Integer truncBits,
305             String spiId,
306             String addr,
307             String udpEncapSockId) {
308         IpSecTransform transform = null;
309         InetAddress inetAddr = NetworkUtils.numericToInetAddress(addr);
310         UdpEncapsulationSocket udpEncapSocket = sUdpEncapHashMap.get(udpEncapSockId);
311         SecurityParameterIndex spi = sSpiHashMap.get(spiId);
312         if (spi == null) {
313             Log.e("IpSec: SPI does not exist for the requested spiId");
314             return null;
315         }
316         byte[] cryptKey = BaseEncoding.base16().decode(cryptKeyHex.toUpperCase());
317         byte[] authKey = BaseEncoding.base16().decode(authKeyHex.toUpperCase());
318         transform = createTransportModeTransform(encAlgo, cryptKey, authAlgo, authKey, truncBits,
319                 spi, inetAddr, udpEncapSocket);
320         if (transform == null) return null;
321         String id = getTransformId(transform);
322         sTransformHashMap.put(id, transform);
323         return id;
324     }
325 
326     @Rpc(description = "Get transform status", returns = "True if transform exists")
ipSecGetTransformStatus(String id)327     public Boolean ipSecGetTransformStatus(String id) {
328         IpSecTransform transform = sTransformHashMap.get(id);
329         if (transform == null) {
330             Log.e("IpSec: Transform does not exist for the requested id");
331             return false;
332         }
333         return true;
334     }
335 
336     @Rpc(description = "Destroy transport mode transform")
ipSecDestroyTransportModeTransform(String id)337     public void ipSecDestroyTransportModeTransform(String id) {
338         IpSecTransform transform = sTransformHashMap.get(id);
339         if (transform == null) {
340             Log.e("IpSec: Transform does not exist for the requested id");
341             return;
342         }
343         transform.close();
344         sTransformHashMap.remove(id);
345     }
346 
347     @Rpc(description = "Open UDP encap socket", returns = "Hash of UDP encap socket object")
ipSecOpenUdpEncapsulationSocket( @pcParametername = "port") @pcOptional Integer port)348     public String ipSecOpenUdpEncapsulationSocket(
349             @RpcParameter(name = "port") @RpcOptional Integer port) {
350         UdpEncapsulationSocket udpEncapSocket = null;
351         if (port == null) {
352             udpEncapSocket = openUdpEncapSocket();
353         } else {
354             udpEncapSocket = openUdpEncapSocket(port.intValue());
355         }
356         if (udpEncapSocket == null) return null;
357         String id = getUdpEncapSockId(udpEncapSocket);
358         sUdpEncapHashMap.put(id, udpEncapSocket);
359         return id;
360     }
361 
362     @Rpc(description = "Close UDP encapsulation socket", returns = "True if socket is closed")
ipSecCloseUdpEncapsulationSocket(String id)363     public Boolean ipSecCloseUdpEncapsulationSocket(String id) {
364         try {
365             UdpEncapsulationSocket udpEncapSocket = sUdpEncapHashMap.get(id);
366             udpEncapSocket.close();
367             sUdpEncapHashMap.remove(id);
368             return true;
369         } catch (IOException e) {
370             Log.e("IpSec: Failed to close udp encap socket " + e.toString());
371         }
372         return false;
373     }
374 
375     @Rpc(description = "Allocate a Security Parameter Index", returns = "Hash of SPI object")
ipSecAllocateSecurityParameterIndex( @pcParametername = "addr") String addr, @RpcParameter(name = "requestedSpi") @RpcOptional Integer requestedSpi)376     public String ipSecAllocateSecurityParameterIndex(
377             @RpcParameter(name = "addr") String addr,
378             @RpcParameter(name = "requestedSpi") @RpcOptional Integer requestedSpi) {
379         InetAddress inetAddr = NetworkUtils.numericToInetAddress(addr);
380         SecurityParameterIndex spi = null;
381         if (requestedSpi == null) {
382             spi = allocateSpi(inetAddr);
383         } else {
384             spi = allocateSpi(inetAddr, requestedSpi.intValue());
385         }
386         if (spi == null) return null;
387         String id = getSpiId(spi);
388         sSpiHashMap.put(id, spi);
389         return id;
390     }
391 
392     @Rpc(description = "Get Security Parameter Index", returns = "Returns SPI value")
ipSecGetSecurityParameterIndex(String id)393     public Integer ipSecGetSecurityParameterIndex(String id) {
394         SecurityParameterIndex spi = sSpiHashMap.get(id);
395         if (spi == null) {
396             Log.d("IpSec: SPI does not exist for the requested id");
397             return 0;
398         }
399         return spi.getSpi();
400     }
401 
402     @Rpc(description = "Release a Security Parameter Index")
ipSecReleaseSecurityParameterIndex(String id)403     public void ipSecReleaseSecurityParameterIndex(String id) {
404         SecurityParameterIndex spi = sSpiHashMap.get(id);
405         if (spi == null) {
406             Log.d("IpSec: SPI does not exist for the requested id");
407             return;
408         }
409         spi.close();
410         sSpiHashMap.remove(id);
411     }
412 
413     @Override
shutdown()414     public void shutdown() {}
415 }
416