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