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.IkeProtocolException;
21 
22 import com.android.internal.net.ipsec.ike.crypto.IkeMacPrf;
23 import com.android.internal.net.ipsec.ike.exceptions.AuthenticationFailedException;
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