xref: /aosp_15_r20/external/sl4a/Common/src/com/googlecode/android_scripting/facade/net/IpSecManagerFacade.java (revision 456ef56af69dcf0481dd36cc45216c4002d72fa3)
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.InetAddresses;
22 import android.net.IpSecAlgorithm;
23 import android.net.IpSecManager;
24 import android.net.IpSecManager.ResourceUnavailableException;
25 import android.net.IpSecManager.SecurityParameterIndex;
26 import android.net.IpSecManager.SpiUnavailableException;
27 import android.net.IpSecManager.UdpEncapsulationSocket;
28 import android.net.IpSecTransform;
29 import android.net.IpSecTransform.Builder;
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      * Method to retrieve UdpEncapsulationSocket from hash key
144      * @param id : Hash key in String
145      * @return UdpEncapsulationSocket object
146      */
getUdpEncapsulationSocket(String id)147     public static UdpEncapsulationSocket getUdpEncapsulationSocket(String id) {
148         return sUdpEncapHashMap.get(id);
149     }
150 
151     /**
152      * Apply transport mode transform to FileDescriptor
153      * @param socketFd : Hash key of FileDescriptor object
154      * @param direction : In or Out direction to apply transform to
155      * @param id : Hash key of the transform
156      * @return True if transform is applied successfully
157      */
158     @Rpc(description = "Apply transport mode transform to FileDescriptor", returns = "True/False")
ipSecApplyTransportModeTransformFileDescriptor( String socketFd, Integer direction, String id)159     public Boolean ipSecApplyTransportModeTransformFileDescriptor(
160             String socketFd,
161             Integer direction,
162             String id) {
163         if (socketFd == null) {
164             Log.e("IpSec: Received null FileDescriptor key");
165             return false;
166         }
167         FileDescriptor fd = SocketFacade.getFileDescriptor(socketFd);
168         IpSecTransform transform = sTransformHashMap.get(id);
169         if (transform == null) {
170             Log.e("IpSec: Transform does not exist for the requested id");
171             return false;
172         }
173         try {
174             mIpSecManager.applyTransportModeTransform(fd, direction.intValue(), transform);
175         } catch (IOException e) {
176             Log.e("IpSec: Cannot apply transform to socket " + e.toString());
177             return false;
178         }
179         return true;
180     }
181 
182     /**
183      * Remove transport mode transform from a FileDescriptor
184      * @param socketFd : Hash key of FileDescriptor object
185      * @returns True if transform is removed successfully
186      */
187     @Rpc(description = "Remove transport mode transform to FileDescriptor", returns = "True/False")
ipSecRemoveTransportModeTransformsFileDescriptor(String socketFd)188     public Boolean ipSecRemoveTransportModeTransformsFileDescriptor(String socketFd) {
189         if (socketFd == null) {
190             Log.e("IpSec: Received null FileDescriptor key");
191             return false;
192         }
193         FileDescriptor fd = SocketFacade.getFileDescriptor(socketFd);
194         try {
195             mIpSecManager.removeTransportModeTransforms(fd);
196             return true;
197         } catch (IOException e) {
198             Log.e("IpSec: Failed to remove transform " + e.toString());
199         }
200         return false;
201     }
202 
203     /**
204      * Apply transport mode transform to DatagramSocket
205      * @param socketId : Hash key of DatagramSocket
206      * @param direction : In or Out direction to apply transform to
207      * @param transformId : Hash key of Transform to apply
208      * @return True if transform is applied successfully
209      */
210     @Rpc(description = "Apply transport mode transform to DatagramSocket", returns = "True/False")
ipSecApplyTransportModeTransformDatagramSocket( String socketId, Integer direction, String transformId)211     public Boolean ipSecApplyTransportModeTransformDatagramSocket(
212             String socketId,
213             Integer direction,
214             String transformId) {
215         if (socketId == null) {
216             Log.e("IpSec: Received null DatagramSocket key");
217             return false;
218         }
219         DatagramSocket socket = SocketFacade.getDatagramSocket(socketId);
220         IpSecTransform transform = sTransformHashMap.get(transformId);
221         if (transform == null) {
222             Log.e("IpSec: Transform does not exist for the requested id");
223             return false;
224         }
225         try {
226             mIpSecManager.applyTransportModeTransform(socket, direction.intValue(), transform);
227         } catch (IOException e) {
228             Log.e("IpSec: Cannot apply transform to socket " + e.toString());
229             return false;
230         }
231         return true;
232     }
233 
234     /**
235      * Remove transport mode transform from DatagramSocket
236      * @param socketId : Hash key of DatagramSocket
237      * @return True if removing transform is successful
238      */
239     @Rpc(description = "Remove transport mode tranform from DatagramSocket", returns = "True/False")
ipSecRemoveTransportModeTransformsDatagramSocket(String socketId)240     public Boolean ipSecRemoveTransportModeTransformsDatagramSocket(String socketId) {
241         if (socketId == null) {
242             Log.e("IpSec: Received null DatagramSocket key");
243             return false;
244         }
245         DatagramSocket socket = SocketFacade.getDatagramSocket(socketId);
246         try {
247             mIpSecManager.removeTransportModeTransforms(socket);
248             return true;
249         } catch (IOException e) {
250             Log.e("IpSec: Failed to remove transform " + e.toString());
251         }
252         return false;
253     }
254 
255     /**
256      * Apply transport mode transform to DatagramSocket
257      * @param socketId : Hash key of Socket
258      * @param direction : In or Out direction to apply transform to
259      * @param transformId : Hash key of Transform to apply
260      * @return True if transform is applied successfully
261      */
262     @Rpc(description = "Apply transport mode transform to Socket", returns = "True/False")
ipSecApplyTransportModeTransformSocket( String socketId, Integer direction, String transformId)263     public Boolean ipSecApplyTransportModeTransformSocket(
264             String socketId,
265             Integer direction,
266             String transformId) {
267         if (socketId == null) {
268             Log.e("IpSec: Received null Socket key");
269             return false;
270         }
271         Socket socket = SocketFacade.getSocket(socketId);
272         IpSecTransform transform = sTransformHashMap.get(transformId);
273         if (transform == null) {
274             Log.e("IpSec: Transform does not exist for the requested id");
275             return false;
276         }
277         try {
278             mIpSecManager.applyTransportModeTransform(socket, direction.intValue(), transform);
279         } catch (IOException e) {
280             Log.e("IpSec: Cannot apply transform to socket " + e.toString());
281             return false;
282         }
283         return true;
284     }
285 
286     /**
287      * Remove transport mode transform from Socket
288      * @param socketId : Hash key of DatagramSocket
289      * @return True if removing transform is successful
290      */
291     @Rpc(description = "Remove transport mode tranform from Socket", returns = "True/False")
ipSecRemoveTransportModeTransformsSocket(String socketId)292     public Boolean ipSecRemoveTransportModeTransformsSocket(String socketId) {
293         if (socketId == null) {
294             Log.e("IpSec: Received null Socket key");
295             return false;
296         }
297         Socket socket = SocketFacade.getSocket(socketId);
298         try {
299             mIpSecManager.removeTransportModeTransforms(socket);
300             return true;
301         } catch (IOException e) {
302             Log.e("IpSec: Failed to remove transform " + e.toString());
303         }
304         return false;
305     }
306 
307     @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)308     public String ipSecCreateTransportModeTransform(
309             String encAlgo,
310             String cryptKeyHex,
311             String authAlgo,
312             String authKeyHex,
313             Integer truncBits,
314             String spiId,
315             String addr,
316             String udpEncapSockId) {
317         IpSecTransform transform = null;
318         InetAddress inetAddr = InetAddresses.parseNumericAddress(addr);
319         UdpEncapsulationSocket udpEncapSocket = sUdpEncapHashMap.get(udpEncapSockId);
320         SecurityParameterIndex spi = sSpiHashMap.get(spiId);
321         if (spi == null) {
322             Log.e("IpSec: SPI does not exist for the requested spiId");
323             return null;
324         }
325         byte[] cryptKey = BaseEncoding.base16().decode(cryptKeyHex.toUpperCase());
326         byte[] authKey = BaseEncoding.base16().decode(authKeyHex.toUpperCase());
327         transform = createTransportModeTransform(encAlgo, cryptKey, authAlgo, authKey, truncBits,
328                 spi, inetAddr, udpEncapSocket);
329         if (transform == null) return null;
330         String id = getTransformId(transform);
331         sTransformHashMap.put(id, transform);
332         return id;
333     }
334 
335     @Rpc(description = "Get transform status", returns = "True if transform exists")
ipSecGetTransformStatus(String id)336     public Boolean ipSecGetTransformStatus(String id) {
337         IpSecTransform transform = sTransformHashMap.get(id);
338         if (transform == null) {
339             Log.e("IpSec: Transform does not exist for the requested id");
340             return false;
341         }
342         return true;
343     }
344 
345     @Rpc(description = "Destroy transport mode transform")
ipSecDestroyTransportModeTransform(String id)346     public void ipSecDestroyTransportModeTransform(String id) {
347         IpSecTransform transform = sTransformHashMap.get(id);
348         if (transform == null) {
349             Log.e("IpSec: Transform does not exist for the requested id");
350             return;
351         }
352         transform.close();
353         sTransformHashMap.remove(id);
354     }
355 
356     @Rpc(description = "Open UDP encap socket", returns = "Hash of UDP encap socket object")
ipSecOpenUdpEncapsulationSocket( @pcParametername = "port") @pcOptional Integer port)357     public String ipSecOpenUdpEncapsulationSocket(
358             @RpcParameter(name = "port") @RpcOptional Integer port) {
359         UdpEncapsulationSocket udpEncapSocket = null;
360         if (port == null) {
361             udpEncapSocket = openUdpEncapSocket();
362         } else {
363             udpEncapSocket = openUdpEncapSocket(port.intValue());
364         }
365         if (udpEncapSocket == null) return null;
366         String id = getUdpEncapSockId(udpEncapSocket);
367         sUdpEncapHashMap.put(id, udpEncapSocket);
368         return id;
369     }
370 
371     @Rpc(description = "Close UDP encapsulation socket", returns = "True if socket is closed")
ipSecCloseUdpEncapsulationSocket(String id)372     public Boolean ipSecCloseUdpEncapsulationSocket(String id) {
373         try {
374             UdpEncapsulationSocket udpEncapSocket = sUdpEncapHashMap.get(id);
375             udpEncapSocket.close();
376             sUdpEncapHashMap.remove(id);
377             return true;
378         } catch (IOException e) {
379             Log.e("IpSec: Failed to close udp encap socket " + e.toString());
380         }
381         return false;
382     }
383 
384     @Rpc(description = "Allocate a Security Parameter Index", returns = "Hash of SPI object")
ipSecAllocateSecurityParameterIndex( @pcParametername = "addr") String addr, @RpcParameter(name = "requestedSpi") @RpcOptional Integer requestedSpi)385     public String ipSecAllocateSecurityParameterIndex(
386             @RpcParameter(name = "addr") String addr,
387             @RpcParameter(name = "requestedSpi") @RpcOptional Integer requestedSpi) {
388         InetAddress inetAddr = InetAddresses.parseNumericAddress(addr);
389         SecurityParameterIndex spi = null;
390         if (requestedSpi == null) {
391             spi = allocateSpi(inetAddr);
392         } else {
393             spi = allocateSpi(inetAddr, requestedSpi.intValue());
394         }
395         if (spi == null) return null;
396         String id = getSpiId(spi);
397         sSpiHashMap.put(id, spi);
398         return id;
399     }
400 
401     @Rpc(description = "Get Security Parameter Index", returns = "Returns SPI value")
ipSecGetSecurityParameterIndex(String id)402     public Integer ipSecGetSecurityParameterIndex(String id) {
403         SecurityParameterIndex spi = sSpiHashMap.get(id);
404         if (spi == null) {
405             Log.d("IpSec: SPI does not exist for the requested id");
406             return 0;
407         }
408         return spi.getSpi();
409     }
410 
411     @Rpc(description = "Release a Security Parameter Index")
ipSecReleaseSecurityParameterIndex(String id)412     public void ipSecReleaseSecurityParameterIndex(String id) {
413         SecurityParameterIndex spi = sSpiHashMap.get(id);
414         if (spi == null) {
415             Log.d("IpSec: SPI does not exist for the requested id");
416             return;
417         }
418         spi.close();
419         sSpiHashMap.remove(id);
420     }
421 
422     @Override
shutdown()423     public void shutdown() {}
424 }
425