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