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.net.ipsec.ike.IkeDerAsn1DnIdentification; 20 import android.net.ipsec.ike.IkeFqdnIdentification; 21 import android.net.ipsec.ike.IkeIdentification; 22 import android.net.ipsec.ike.IkeIpv4AddrIdentification; 23 import android.net.ipsec.ike.IkeIpv6AddrIdentification; 24 import android.net.ipsec.ike.IkeKeyIdIdentification; 25 import android.net.ipsec.ike.IkeRfc822AddrIdentification; 26 import android.net.ipsec.ike.exceptions.IkeProtocolException; 27 28 import com.android.internal.net.ipsec.ike.exceptions.AuthenticationFailedException; 29 import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException; 30 31 import java.nio.ByteBuffer; 32 import java.security.cert.X509Certificate; 33 34 /** 35 * IkeIdPayload represents an Identification Initiator Payload or an Identification Responder 36 * Payload. 37 * 38 * <p>Identification Initiator Payload and Identification Responder Payload have same format but 39 * different payload type. 40 * 41 * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.5">RFC 7296, Internet Key Exchange 42 * Protocol Version 2 (IKEv2)</a> 43 */ 44 public final class IkeIdPayload extends IkePayload { 45 // Length of ID Payload header in octets. 46 private static final int ID_HEADER_LEN = 4; 47 // Length of reserved field in octets. 48 private static final int ID_HEADER_RESERVED_LEN = 3; 49 50 public final IkeIdentification ikeId; 51 52 /** 53 * Construct IkeIdPayload for received IKE packet in the context of {@link IkePayloadFactory}. 54 * 55 * @param critical indicates if it is a critical payload. 56 * @param payloadBody payload body in byte array. 57 * @param isInitiator indicates whether this payload contains the ID of IKE initiator or IKE 58 * responder. 59 * @throws IkeProtocolException for decoding error. 60 */ IkeIdPayload(boolean critical, byte[] payloadBody, boolean isInitiator)61 IkeIdPayload(boolean critical, byte[] payloadBody, boolean isInitiator) 62 throws IkeProtocolException { 63 super((isInitiator ? PAYLOAD_TYPE_ID_INITIATOR : PAYLOAD_TYPE_ID_RESPONDER), critical); 64 // TODO: b/119791832 Add helper method for checking payload body length in superclass. 65 if (payloadBody.length <= ID_HEADER_LEN) { 66 throw new InvalidSyntaxException(getTypeString() + " is too short."); 67 } 68 69 ByteBuffer inputBuffer = ByteBuffer.wrap(payloadBody); 70 int idType = Byte.toUnsignedInt(inputBuffer.get()); 71 72 // Skip reserved field 73 inputBuffer.get(new byte[ID_HEADER_RESERVED_LEN]); 74 75 byte[] idData = new byte[payloadBody.length - ID_HEADER_LEN]; 76 inputBuffer.get(idData); 77 78 switch (idType) { 79 case IkeIdentification.ID_TYPE_IPV4_ADDR: 80 ikeId = new IkeIpv4AddrIdentification(idData); 81 return; 82 case IkeIdentification.ID_TYPE_FQDN: 83 ikeId = new IkeFqdnIdentification(idData); 84 return; 85 case IkeIdentification.ID_TYPE_RFC822_ADDR: 86 ikeId = new IkeRfc822AddrIdentification(idData); 87 return; 88 case IkeIdentification.ID_TYPE_IPV6_ADDR: 89 ikeId = new IkeIpv6AddrIdentification(idData); 90 return; 91 case IkeIdentification.ID_TYPE_DER_ASN1_DN: 92 ikeId = new IkeDerAsn1DnIdentification(idData); 93 return; 94 case IkeIdentification.ID_TYPE_KEY_ID: 95 ikeId = new IkeKeyIdIdentification(idData); 96 return; 97 default: 98 throw new AuthenticationFailedException("Unsupported ID type: " + idType); 99 } 100 } 101 102 /** 103 * Construct IkeIdPayload for an outbound IKE packet. 104 * 105 * @param isInitiator indicates whether this payload contains the ID of IKE initiator or IKE 106 * responder. 107 * @param ikeId the IkeIdentification. 108 */ IkeIdPayload(boolean isInitiator, IkeIdentification ikeId)109 public IkeIdPayload(boolean isInitiator, IkeIdentification ikeId) { 110 super((isInitiator ? PAYLOAD_TYPE_ID_INITIATOR : PAYLOAD_TYPE_ID_RESPONDER), false); 111 this.ikeId = ikeId; 112 } 113 114 /** 115 * Get encoded ID payload body for building or validating an Auth Payload. 116 * 117 * @return the byte array of encoded ID payload body. 118 */ getEncodedPayloadBody()119 public byte[] getEncodedPayloadBody() { 120 ByteBuffer byteBuffer = ByteBuffer.allocate(getPayloadLength() - GENERIC_HEADER_LENGTH); 121 122 byteBuffer 123 .put((byte) ikeId.idType) 124 .put(new byte[ID_HEADER_RESERVED_LEN]) 125 .put(ikeId.getEncodedIdData()); 126 return byteBuffer.array(); 127 } 128 129 /** Validate if the end certificate matches the ID */ validateEndCertIdOrThrow(X509Certificate endCert)130 public void validateEndCertIdOrThrow(X509Certificate endCert) 131 throws AuthenticationFailedException { 132 ikeId.validateEndCertIdOrThrow(endCert); 133 } 134 135 /** 136 * Encode Identification Payload to ByteBuffer. 137 * 138 * @param nextPayload type of payload that follows this payload. 139 * @param byteBuffer destination ByteBuffer that stores encoded payload. 140 */ 141 @Override encodeToByteBuffer(@ayloadType int nextPayload, ByteBuffer byteBuffer)142 protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) { 143 encodePayloadHeaderToByteBuffer(nextPayload, getPayloadLength(), byteBuffer); 144 byteBuffer.put(getEncodedPayloadBody()); 145 } 146 147 /** 148 * Get entire payload length. 149 * 150 * @return entire payload length. 151 */ 152 @Override getPayloadLength()153 protected int getPayloadLength() { 154 return GENERIC_HEADER_LENGTH + ID_HEADER_LEN + ikeId.getEncodedIdData().length; 155 } 156 157 /** 158 * Return the payload type as a String. 159 * 160 * @return the payload type as a String. 161 */ 162 @Override getTypeString()163 public String getTypeString() { 164 switch (payloadType) { 165 case PAYLOAD_TYPE_ID_INITIATOR: 166 return "IDi"; 167 case PAYLOAD_TYPE_ID_RESPONDER: 168 return "IDr"; 169 default: 170 // Won't reach here. 171 throw new IllegalArgumentException( 172 "Invalid Payload Type for Identification Payload."); 173 } 174 } 175 } 176