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.Nullable;
20 import android.net.ipsec.ike.exceptions.IkeProtocolException;
21 
22 import com.android.internal.annotations.VisibleForTesting;
23 import com.android.internal.net.ipsec.ike.crypto.IkeCipher;
24 import com.android.internal.net.ipsec.ike.crypto.IkeMacIntegrity;
25 
26 import java.nio.ByteBuffer;
27 import java.security.GeneralSecurityException;
28 
29 /**
30  * IkeSkPayload represents the common information of an Encrypted and Authenticated Payload and an
31  * Encrypted and Authenticated Fragment Payload.
32  *
33  * <p>It contains other payloads in encrypted form. It is must be the last payload in the message.
34  * It should be the only payload in this implementation.
35  *
36  * <p>Critical bit must be ignored when doing decoding.
37  *
38  * @see <a href="https://tools.ietf.org/html/rfc7296#page-105">RFC 7296, Internet Key Exchange
39  *     Protocol Version 2 (IKEv2)</a>
40  */
41 public class IkeSkPayload extends IkePayload {
42 
43     protected final IkeEncryptedPayloadBody mIkeEncryptedPayloadBody;
44 
45     /**
46      * Construct an instance of IkeSkPayload from decrypting an incoming packet.
47      *
48      * @param critical indicates if it is a critical payload.
49      * @param message the byte array contains the whole IKE message.
50      * @param integrityMac the negotiated integrity algorithm.
51      * @param decryptCipher the negotiated encryption algorithm.
52      * @param integrityKey the negotiated integrity algorithm key.
53      * @param decryptionKey the negotiated decryption key.
54      */
55     @VisibleForTesting
IkeSkPayload( boolean critical, byte[] message, @Nullable IkeMacIntegrity integrityMac, IkeCipher decryptCipher, byte[] integrityKey, byte[] decryptionKey)56     IkeSkPayload(
57             boolean critical,
58             byte[] message,
59             @Nullable IkeMacIntegrity integrityMac,
60             IkeCipher decryptCipher,
61             byte[] integrityKey,
62             byte[] decryptionKey)
63             throws IkeProtocolException, GeneralSecurityException {
64 
65         this(
66                 false /*isSkf*/,
67                 critical,
68                 IkeHeader.IKE_HEADER_LENGTH + GENERIC_HEADER_LENGTH,
69                 message,
70                 integrityMac,
71                 decryptCipher,
72                 integrityKey,
73                 decryptionKey);
74     }
75 
76     /** Construct an instance of IkeSkPayload for testing.*/
77     @VisibleForTesting
IkeSkPayload(boolean isSkf, IkeEncryptedPayloadBody encryptedPayloadBody)78     IkeSkPayload(boolean isSkf, IkeEncryptedPayloadBody encryptedPayloadBody) {
79         super(isSkf ? PAYLOAD_TYPE_SKF : PAYLOAD_TYPE_SK, false/*critical*/);
80         mIkeEncryptedPayloadBody = encryptedPayloadBody;
81     }
82 
83     /** Construct an instance of IkeSkPayload from decrypting an incoming packet. */
IkeSkPayload( boolean isSkf, boolean critical, int encryptedBodyOffset, byte[] message, @Nullable IkeMacIntegrity integrityMac, IkeCipher decryptCipher, byte[] integrityKey, byte[] decryptionKey)84     protected IkeSkPayload(
85             boolean isSkf,
86             boolean critical,
87             int encryptedBodyOffset,
88             byte[] message,
89             @Nullable IkeMacIntegrity integrityMac,
90             IkeCipher decryptCipher,
91             byte[] integrityKey,
92             byte[] decryptionKey)
93             throws IkeProtocolException, GeneralSecurityException {
94         super(isSkf ? PAYLOAD_TYPE_SKF : PAYLOAD_TYPE_SK, critical);
95 
96         // TODO: Support constructing IkeEncryptedPayloadBody using AEAD.
97 
98         mIkeEncryptedPayloadBody =
99                 new IkeEncryptedPayloadBody(
100                         message,
101                         encryptedBodyOffset,
102                         integrityMac,
103                         decryptCipher,
104                         integrityKey,
105                         decryptionKey);
106     }
107 
108     /**
109      * Construct an instance of IkeSkPayload for building outbound packet.
110      *
111      * @param ikeHeader the IKE header.
112      * @param firstPayloadType the type of first payload nested in SkPayload.
113      * @param unencryptedPayloads the encoded payload list to protect.
114      * @param integrityMac the negotiated integrity algorithm.
115      * @param encryptCipher the negotiated encryption algorithm.
116      * @param integrityKey the negotiated integrity algorithm key.
117      * @param encryptionKey the negotiated encryption key.
118      */
119     @VisibleForTesting
IkeSkPayload( IkeHeader ikeHeader, @PayloadType int firstPayloadType, byte[] unencryptedPayloads, @Nullable IkeMacIntegrity integrityMac, IkeCipher encryptCipher, byte[] integrityKey, byte[] encryptionKey)120     IkeSkPayload(
121             IkeHeader ikeHeader,
122             @PayloadType int firstPayloadType,
123             byte[] unencryptedPayloads,
124             @Nullable IkeMacIntegrity integrityMac,
125             IkeCipher encryptCipher,
126             byte[] integrityKey,
127             byte[] encryptionKey) {
128 
129         this(
130                 ikeHeader,
131                 firstPayloadType,
132                 new byte[0] /*skfHeaderBytes*/,
133                 unencryptedPayloads,
134                 integrityMac,
135                 encryptCipher,
136                 integrityKey,
137                 encryptionKey);
138     }
139 
140     /** Construct an instance of IkeSkPayload for building outbound packet. */
141     @VisibleForTesting
IkeSkPayload( IkeHeader ikeHeader, @PayloadType int firstPayloadType, byte[] skfHeaderBytes, byte[] unencryptedPayloads, @Nullable IkeMacIntegrity integrityMac, IkeCipher encryptCipher, byte[] integrityKey, byte[] encryptionKey)142     protected IkeSkPayload(
143             IkeHeader ikeHeader,
144             @PayloadType int firstPayloadType,
145             byte[] skfHeaderBytes,
146             byte[] unencryptedPayloads,
147             @Nullable IkeMacIntegrity integrityMac,
148             IkeCipher encryptCipher,
149             byte[] integrityKey,
150             byte[] encryptionKey) {
151         super(skfHeaderBytes.length == 0 ? PAYLOAD_TYPE_SK : PAYLOAD_TYPE_SKF, false);
152 
153         // TODO: Support constructing IkeEncryptedPayloadBody using AEAD.
154 
155         mIkeEncryptedPayloadBody =
156                 new IkeEncryptedPayloadBody(
157                         ikeHeader,
158                         firstPayloadType,
159                         skfHeaderBytes,
160                         unencryptedPayloads,
161                         integrityMac,
162                         encryptCipher,
163                         integrityKey,
164                         encryptionKey);
165     }
166 
167     /**
168      * Return unencrypted data.
169      *
170      * @return unencrypted data in a byte array.
171      */
getUnencryptedData()172     public byte[] getUnencryptedData() {
173         return mIkeEncryptedPayloadBody.getUnencryptedData();
174     }
175 
176     /**
177      * Encode this payload to a ByteBuffer.
178      *
179      * @param nextPayload type of payload that follows this payload.
180      * @param byteBuffer destination ByteBuffer that stores encoded payload.
181      */
182     @Override
encodeToByteBuffer(@ayloadType int nextPayload, ByteBuffer byteBuffer)183     protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) {
184         encodePayloadHeaderToByteBuffer(nextPayload, getPayloadLength(), byteBuffer);
185         byteBuffer.put(mIkeEncryptedPayloadBody.encode());
186     }
187 
188     /**
189      * Get entire payload length.
190      *
191      * @return entire payload length.
192      */
193     @Override
getPayloadLength()194     protected int getPayloadLength() {
195         return GENERIC_HEADER_LENGTH + mIkeEncryptedPayloadBody.getLength();
196     }
197 
198     /**
199      * Return the payload type as a String.
200      *
201      * @return the payload type as a String.
202      */
203     @Override
getTypeString()204     public String getTypeString() {
205         return "SK";
206     }
207 }
208