• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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