/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.net.ipsec.ike.message; import com.android.internal.net.ipsec.ike.crypto.IkeMacPrf; import com.android.internal.net.ipsec.ike.exceptions.AuthenticationFailedException; import java.nio.ByteBuffer; import java.util.Arrays; /** * IkeAuthPskPayload represents an Authentication Payload using Pre-Shared Key to do authentication. * * @see RFC 7296, Internet Key Exchange * Protocol Version 2 (IKEv2) */ public final class IkeAuthPskPayload extends IkeAuthPayload { // Hex of ASCII characters "Key Pad for IKEv2" for calculating PSK signature. private static final byte[] IKE_KEY_PAD_STRING_ASCII_HEX_BYTES = { (byte) 0x4b, (byte) 0x65, (byte) 0x79, (byte) 0x20, (byte) 0x50, (byte) 0x61, (byte) 0x64, (byte) 0x20, (byte) 0x66, (byte) 0x6f, (byte) 0x72, (byte) 0x20, (byte) 0x49, (byte) 0x4b, (byte) 0x45, (byte) 0x76, (byte) 0x32 }; public final byte[] signature; /** * Construct IkeAuthPskPayload for received IKE packet in the context of {@link * IkePayloadFactory}. */ protected IkeAuthPskPayload(boolean critical, byte[] authData) { super(critical, IkeAuthPayload.AUTH_METHOD_PRE_SHARED_KEY); signature = authData; } /** * Construct IkeAuthPskPayload for an outbound IKE packet. * *

Since IKE library is always a client, outbound IkeAuthPskPayload always signs IKE * initiator's SignedOctets, which is concatenation of the IKE_INIT request message, the Nonce * of IKE responder and the signed ID-Initiator payload body. * * @param psk locally stored pre-shared key * @param ikeInitBytes IKE_INIT request for calculating IKE initiator's SignedOctets. * @param nonce nonce of IKE responder for calculating IKE initiator's SignedOctets. * @param idPayloadBodyBytes ID-Initiator payload body for calculating IKE initiator's * SignedOctets. * @param ikePrf the negotiated PRF. * @param prfKeyBytes the negotiated PRF key. */ public IkeAuthPskPayload( byte[] psk, byte[] ikeInitBytes, byte[] nonce, byte[] idPayloadBodyBytes, IkeMacPrf ikePrf, byte[] prfKeyBytes) { super(false, IkeAuthPayload.AUTH_METHOD_PRE_SHARED_KEY); signature = calculatePskSignature( psk, ikeInitBytes, nonce, idPayloadBodyBytes, ikePrf, prfKeyBytes); } private static byte[] calculatePskSignature( byte[] psk, byte[] ikeInitBytes, byte[] nonce, byte[] idPayloadBodyBytes, IkeMacPrf ikePrf, byte[] prfKeyBytes) { byte[] signingKeyBytes = ikePrf.signBytes(psk, IKE_KEY_PAD_STRING_ASCII_HEX_BYTES); byte[] dataToSignBytes = getSignedOctets(ikeInitBytes, nonce, idPayloadBodyBytes, ikePrf, prfKeyBytes); return ikePrf.signBytes(signingKeyBytes, dataToSignBytes); } /** * Verify received signature in inbound IKE packet. * *

Since IKE library is always a client, inbound IkeAuthPskPayload always signs IKE * responder's SignedOctets, which is concatenation of the IKE_INIT response message, the Nonce * of IKE initiator and the signed ID-Responder payload body. * * @param psk locally stored pre-shared key * @param ikeInitBytes IKE_INIT response for calculating IKE responder's SignedOctets. * @param nonce nonce of IKE initiator for calculating IKE responder's SignedOctets. * @param idPayloadBodyBytes ID-Responder payload body for calculating IKE responder's * SignedOctets. * @param ikePrf the negotiated PRF. * @param prfKeyBytes the negotiated PRF key. * @throws AuthenticationFailedException if received signature is not equal to calculated * signature. */ public void verifyInboundSignature( byte[] psk, byte[] ikeInitBytes, byte[] nonce, byte[] idPayloadBodyBytes, IkeMacPrf ikePrf, byte[] prfKeyBytes) throws AuthenticationFailedException { byte[] calculatedSignature = calculatePskSignature( psk, ikeInitBytes, nonce, idPayloadBodyBytes, ikePrf, prfKeyBytes); if (!Arrays.equals(signature, calculatedSignature)) { throw new AuthenticationFailedException("Signature verification failed."); } } @Override protected void encodeAuthDataToByteBuffer(ByteBuffer byteBuffer) { byteBuffer.put(signature); } @Override protected int getAuthDataLength() { return signature.length; } @Override public String getTypeString() { return "Auth(PSK)"; } }