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.android.internal.net.ipsec.ike.message; 18 19 import android.annotation.IntDef; 20 import android.net.ipsec.ike.exceptions.AuthenticationFailedException; 21 import android.net.ipsec.ike.exceptions.IkeProtocolException; 22 23 import com.android.internal.net.ipsec.ike.crypto.IkeMacPrf; 24 25 import java.lang.annotation.Retention; 26 import java.lang.annotation.RetentionPolicy; 27 import java.nio.ByteBuffer; 28 29 /** 30 * IkeAuthPayload is an abstract class that represents the common information for all Authentication 31 * Payload with different authentication methods. 32 * 33 * <p>Authentication Payload using different authentication method should implement its own 34 * subclasses with its own logic for signing data, decoding auth data and verifying signature. 35 * 36 * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.8">RFC 7296, Internet Key Exchange 37 * Protocol Version 2 (IKEv2)</a> 38 */ 39 public abstract class IkeAuthPayload extends IkePayload { 40 // Length of header of Authentication Payload in octets 41 private static final int AUTH_HEADER_LEN = 4; 42 // Length of reserved field in octets 43 private static final int AUTH_RESERVED_FIELD_LEN = 3; 44 45 /** @hide */ 46 @Retention(RetentionPolicy.SOURCE) 47 @IntDef({ 48 AUTH_METHOD_RSA_DIGITAL_SIGN, 49 AUTH_METHOD_PRE_SHARED_KEY, 50 AUTH_METHOD_GENERIC_DIGITAL_SIGN 51 }) 52 public @interface AuthMethod {} 53 54 // RSA signature-based authentication. Use SHA-1 for hash algorithm. 55 public static final int AUTH_METHOD_RSA_DIGITAL_SIGN = 1; 56 // PSK-based authentication. 57 public static final int AUTH_METHOD_PRE_SHARED_KEY = 2; 58 // Generic method for all types of signature-based authentication. 59 public static final int AUTH_METHOD_GENERIC_DIGITAL_SIGN = 14; 60 61 @AuthMethod public final int authMethod; 62 IkeAuthPayload(boolean critical, int authMethod)63 protected IkeAuthPayload(boolean critical, int authMethod) { 64 super(PAYLOAD_TYPE_AUTH, critical); 65 this.authMethod = authMethod; 66 } 67 getIkeAuthPayload(boolean critical, byte[] payloadBody)68 protected static IkeAuthPayload getIkeAuthPayload(boolean critical, byte[] payloadBody) 69 throws IkeProtocolException { 70 ByteBuffer inputBuffer = ByteBuffer.wrap(payloadBody); 71 72 int authMethod = Byte.toUnsignedInt(inputBuffer.get()); 73 // Skip reserved field 74 byte[] reservedField = new byte[AUTH_RESERVED_FIELD_LEN]; 75 inputBuffer.get(reservedField); 76 77 byte[] authData = new byte[payloadBody.length - AUTH_HEADER_LEN]; 78 inputBuffer.get(authData); 79 switch (authMethod) { 80 case AUTH_METHOD_PRE_SHARED_KEY: 81 return new IkeAuthPskPayload(critical, authData); 82 case AUTH_METHOD_RSA_DIGITAL_SIGN: 83 return new IkeAuthDigitalSignPayload( 84 critical, AUTH_METHOD_RSA_DIGITAL_SIGN, authData); 85 case AUTH_METHOD_GENERIC_DIGITAL_SIGN: 86 return new IkeAuthDigitalSignPayload( 87 critical, AUTH_METHOD_GENERIC_DIGITAL_SIGN, authData); 88 default: 89 throw new AuthenticationFailedException("Unsupported authentication method"); 90 } 91 } 92 93 // When not using EAP, the peers are authenticated by having each sign a block of data named as 94 // SignedOctets. IKE initiator's SignedOctets are the concatenation of the IKE_INIT request 95 // message, the Nonce of IKE responder and the signed ID-Initiator payload body. Similarly, IKE 96 // responder's SignedOctets are the concatenation of the IKE_INIT response message, the Nonce of 97 // IKE initiator and the signed ID-Responder payload body. getSignedOctets( byte[] ikeInitBytes, byte[] nonce, byte[] idPayloadBodyBytes, IkeMacPrf ikePrf, byte[] prfKeyBytes)98 protected static byte[] getSignedOctets( 99 byte[] ikeInitBytes, 100 byte[] nonce, 101 byte[] idPayloadBodyBytes, 102 IkeMacPrf ikePrf, 103 byte[] prfKeyBytes) { 104 byte[] signedidPayloadBodyBytes = ikePrf.signBytes(prfKeyBytes, idPayloadBodyBytes); 105 106 ByteBuffer buffer = 107 ByteBuffer.allocate( 108 ikeInitBytes.length + nonce.length + signedidPayloadBodyBytes.length); 109 buffer.put(ikeInitBytes).put(nonce).put(signedidPayloadBodyBytes); 110 111 return buffer.array(); 112 } 113 114 @Override encodeToByteBuffer(@ayloadType int nextPayload, ByteBuffer byteBuffer)115 protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) { 116 encodePayloadHeaderToByteBuffer(nextPayload, getPayloadLength(), byteBuffer); 117 byteBuffer.put((byte) authMethod).put(new byte[AUTH_RESERVED_FIELD_LEN]); 118 encodeAuthDataToByteBuffer(byteBuffer); 119 } 120 121 @Override getPayloadLength()122 protected int getPayloadLength() { 123 return GENERIC_HEADER_LENGTH + AUTH_HEADER_LEN + getAuthDataLength(); 124 } 125 encodeAuthDataToByteBuffer(ByteBuffer byteBuffer)126 protected abstract void encodeAuthDataToByteBuffer(ByteBuffer byteBuffer); 127 getAuthDataLength()128 protected abstract int getAuthDataLength(); 129 } 130