1 /* 2 * Copyright (C) 2019 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 static android.net.ipsec.ike.IkeManager.getIkeLog; 20 21 import android.annotation.StringDef; 22 import android.net.ipsec.ike.exceptions.AuthenticationFailedException; 23 import android.net.ipsec.ike.exceptions.IkeProtocolException; 24 import android.net.ipsec.ike.exceptions.InvalidSyntaxException; 25 import android.util.ArraySet; 26 27 import com.android.internal.annotations.VisibleForTesting; 28 import com.android.internal.net.ipsec.ike.crypto.IkeMacPrf; 29 import com.android.internal.net.ipsec.ike.message.IkeAuthPayload.AuthMethod; 30 31 import java.lang.annotation.Retention; 32 import java.lang.annotation.RetentionPolicy; 33 import java.nio.ByteBuffer; 34 import java.security.InvalidKeyException; 35 import java.security.NoSuchAlgorithmException; 36 import java.security.PrivateKey; 37 import java.security.ProviderException; 38 import java.security.Signature; 39 import java.security.SignatureException; 40 import java.security.cert.X509Certificate; 41 import java.util.Arrays; 42 import java.util.Set; 43 44 /** 45 * IkeAuthDigitalSignPayload represents Authentication Payload using a specific or generic digital 46 * signature authentication method. 47 * 48 * <p>If AUTH_METHOD_RSA_DIGITAL_SIGN is used, then the hash algorithm is SHA1. If 49 * AUTH_METHOD_GENERIC_DIGITAL_SIGN is used, the signature algorithm and hash algorithm are 50 * extracted from authentication data. 51 * 52 * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.8">RFC 7296, Internet Key Exchange 53 * Protocol Version 2 (IKEv2)</a> 54 * @see <a href="https://tools.ietf.org/html/rfc7427">RFC 7427, Signature Authentication in the 55 * Internet Key Exchange Version 2 (IKEv2)</a> 56 */ 57 public class IkeAuthDigitalSignPayload extends IkeAuthPayload { 58 private static final String TAG = IkeAuthDigitalSignPayload.class.getSimpleName(); 59 60 private static final String KEY_ALGO_NAME = "RSA"; 61 private static final byte SIGNATURE_ALGO_ASN1_BYTES_LEN = (byte) 15; 62 private static final byte SIGNATURE_ALGO_ASN1_BYTES_LEN_LEN = (byte) 1; 63 64 // Byte arrays of DER encoded identifier ASN.1 objects that indicates the algorithm used to 65 // generate the signature, extracted from 66 // <a href="https://tools.ietf.org/html/rfc7427#appendix-A"> RFC 7427. There is no need to 67 // understand the encoding process. They are just constants to indicate the algorithm type. 68 private static final byte[] PKI_ALGO_ID_DER_BYTES_RSA_SHA1 = { 69 (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, 70 (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, 71 (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, 72 (byte) 0x05, (byte) 0x05, (byte) 0x00 73 }; 74 private static final byte[] PKI_ALGO_ID_DER_BYTES_RSA_SHA2_256 = { 75 (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, 76 (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, 77 (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, 78 (byte) 0x0b, (byte) 0x05, (byte) 0x00 79 }; 80 private static final byte[] PKI_ALGO_ID_DER_BYTES_RSA_SHA2_384 = { 81 (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, 82 (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, 83 (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, 84 (byte) 0x0c, (byte) 0x05, (byte) 0x00 85 }; 86 private static final byte[] PKI_ALGO_ID_DER_BYTES_RSA_SHA2_512 = { 87 (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, 88 (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, 89 (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, 90 (byte) 0x0d, (byte) 0x05, (byte) 0x00 91 }; 92 93 // Length of ASN.1 object length field. 94 private static final int SIGNATURE_ALGO_ASN1_LEN_LEN = 1; 95 96 // Currently we only support RSA for signature algorithm. 97 @Retention(RetentionPolicy.SOURCE) 98 @StringDef({ 99 SIGNATURE_ALGO_RSA_SHA1, 100 SIGNATURE_ALGO_RSA_SHA2_256, 101 SIGNATURE_ALGO_RSA_SHA2_384, 102 SIGNATURE_ALGO_RSA_SHA2_512 103 }) 104 @VisibleForTesting 105 @interface SignatureAlgo {} 106 107 public static final String SIGNATURE_ALGO_RSA_SHA1 = "SHA1withRSA"; 108 public static final String SIGNATURE_ALGO_RSA_SHA2_256 = "SHA256withRSA"; 109 public static final String SIGNATURE_ALGO_RSA_SHA2_384 = "SHA384withRSA"; 110 public static final String SIGNATURE_ALGO_RSA_SHA2_512 = "SHA512withRSA"; 111 112 // IKEv2 types for hash algorithms. 113 public static final short HASH_ALGORITHM_RSA_SHA1 = 1; 114 public static final short HASH_ALGORITHM_RSA_SHA2_256 = 2; 115 public static final short HASH_ALGORITHM_RSA_SHA2_384 = 3; 116 public static final short HASH_ALGORITHM_RSA_SHA2_512 = 4; 117 public static final short[] ALL_SIGNATURE_ALGO_TYPES = 118 new short[] { 119 HASH_ALGORITHM_RSA_SHA1, 120 HASH_ALGORITHM_RSA_SHA2_256, 121 HASH_ALGORITHM_RSA_SHA2_384, 122 HASH_ALGORITHM_RSA_SHA2_512 123 }; 124 private static final Set<Short> ALL_SIGNATURE_ALGO_TYPES_SET = new ArraySet<>(); 125 126 static { 127 ALL_SIGNATURE_ALGO_TYPES_SET.add(HASH_ALGORITHM_RSA_SHA1); 128 ALL_SIGNATURE_ALGO_TYPES_SET.add(HASH_ALGORITHM_RSA_SHA2_256); 129 ALL_SIGNATURE_ALGO_TYPES_SET.add(HASH_ALGORITHM_RSA_SHA2_384); 130 ALL_SIGNATURE_ALGO_TYPES_SET.add(HASH_ALGORITHM_RSA_SHA2_512); 131 } 132 133 public final String signatureAndHashAlgos; 134 public final byte[] signature; 135 IkeAuthDigitalSignPayload( boolean critical, @AuthMethod int authMethod, byte[] authData)136 protected IkeAuthDigitalSignPayload( 137 boolean critical, @AuthMethod int authMethod, byte[] authData) 138 throws IkeProtocolException { 139 super(critical, authMethod); 140 switch (authMethod) { 141 case AUTH_METHOD_RSA_DIGITAL_SIGN: 142 signatureAndHashAlgos = SIGNATURE_ALGO_RSA_SHA1; 143 signature = authData; 144 break; 145 case AUTH_METHOD_GENERIC_DIGITAL_SIGN: 146 ByteBuffer inputBuffer = ByteBuffer.wrap(authData); 147 148 // Get signature algorithm. 149 int signAlgoLen = Byte.toUnsignedInt(inputBuffer.get()); 150 byte[] signAlgoBytes = new byte[signAlgoLen]; 151 inputBuffer.get(signAlgoBytes); 152 signatureAndHashAlgos = bytesToJavaStandardSignAlgoName(signAlgoBytes); 153 154 // Get signature. 155 signature = new byte[authData.length - SIGNATURE_ALGO_ASN1_LEN_LEN - signAlgoLen]; 156 inputBuffer.get(signature); 157 break; 158 default: 159 throw new IllegalArgumentException("Unrecognized authentication method."); 160 } 161 } 162 163 /** 164 * Construct IkeAuthDigitalSignPayload for an outbound IKE packet. 165 * 166 * <p>Since IKE library is always a client, outbound IkeAuthDigitalSignPayload always signs IKE 167 * initiator's SignedOctets, which is concatenation of the IKE_INIT request message, the Nonce 168 * of IKE responder and the signed ID-Initiator payload body. 169 * 170 * <p>Caller MUST validate that the signatureAlgoName is supported by IKE library. 171 * 172 * @param signatureAlgoName the name of the algorithm requested. See the Signature section in 173 * the <a href= "{@docRoot}/../technotes/guides/security/StandardNames.html#Signature"> Java 174 * Cryptography Architecture Standard Algorithm Name Documentation</a> for information about 175 * standard algorithm names. 176 * @param privateKey the private key of the identity whose signature is going to be generated. 177 * @param ikeInitBytes IKE_INIT request for calculating IKE initiator's SignedOctets. 178 * @param nonce nonce of IKE responder for calculating IKE initiator's SignedOctets. 179 * @param idPayloadBodyBytes ID-Initiator payload body for calculating IKE initiator's 180 * SignedOctets. 181 * @param ikePrf the negotiated PRF. 182 * @param prfKeyBytes the negotiated PRF initiator key. 183 */ IkeAuthDigitalSignPayload( String signatureAlgoName, PrivateKey privateKey, byte[] ikeInitBytes, byte[] nonce, byte[] idPayloadBodyBytes, IkeMacPrf ikePrf, byte[] prfKeyBytes)184 public IkeAuthDigitalSignPayload( 185 String signatureAlgoName, 186 PrivateKey privateKey, 187 byte[] ikeInitBytes, 188 byte[] nonce, 189 byte[] idPayloadBodyBytes, 190 IkeMacPrf ikePrf, 191 byte[] prfKeyBytes) { 192 super(false, IkeAuthPayload.AUTH_METHOD_GENERIC_DIGITAL_SIGN); 193 byte[] dataToSignBytes = 194 getSignedOctets(ikeInitBytes, nonce, idPayloadBodyBytes, ikePrf, prfKeyBytes); 195 196 try { 197 Signature signGen = Signature.getInstance(signatureAlgoName); 198 signGen.initSign(privateKey); 199 signGen.update(dataToSignBytes); 200 201 signature = signGen.sign(); 202 signatureAndHashAlgos = signatureAlgoName; 203 } catch (SignatureException | InvalidKeyException e) { 204 throw new IllegalArgumentException("Signature generation failed", e); 205 } catch (NoSuchAlgorithmException e) { 206 throw new ProviderException( 207 "Security Provider does not support " 208 + KEY_ALGO_NAME 209 + " or " 210 + signatureAlgoName); 211 } 212 } 213 javaStandardSignAlgoNameToAsn1Bytes(String javaSignatureAndHashAlgo)214 private byte[] javaStandardSignAlgoNameToAsn1Bytes(String javaSignatureAndHashAlgo) { 215 switch (javaSignatureAndHashAlgo) { 216 case SIGNATURE_ALGO_RSA_SHA1: 217 return PKI_ALGO_ID_DER_BYTES_RSA_SHA1; 218 case SIGNATURE_ALGO_RSA_SHA2_256: 219 return PKI_ALGO_ID_DER_BYTES_RSA_SHA2_256; 220 case SIGNATURE_ALGO_RSA_SHA2_384: 221 return PKI_ALGO_ID_DER_BYTES_RSA_SHA2_384; 222 case SIGNATURE_ALGO_RSA_SHA2_512: 223 return PKI_ALGO_ID_DER_BYTES_RSA_SHA2_512; 224 default: 225 throw new IllegalArgumentException("Impossible! We used an unsupported algo"); 226 } 227 } 228 bytesToJavaStandardSignAlgoName(byte[] signAlgoBytes)229 private String bytesToJavaStandardSignAlgoName(byte[] signAlgoBytes) 230 throws AuthenticationFailedException { 231 if (Arrays.equals(PKI_ALGO_ID_DER_BYTES_RSA_SHA1, signAlgoBytes)) { 232 return SIGNATURE_ALGO_RSA_SHA1; 233 } else if (Arrays.equals(PKI_ALGO_ID_DER_BYTES_RSA_SHA2_256, signAlgoBytes)) { 234 return SIGNATURE_ALGO_RSA_SHA2_256; 235 } else if (Arrays.equals(PKI_ALGO_ID_DER_BYTES_RSA_SHA2_384, signAlgoBytes)) { 236 return SIGNATURE_ALGO_RSA_SHA2_384; 237 } else if (Arrays.equals(PKI_ALGO_ID_DER_BYTES_RSA_SHA2_512, signAlgoBytes)) { 238 return SIGNATURE_ALGO_RSA_SHA2_512; 239 } else { 240 throw new AuthenticationFailedException( 241 "Unrecognized ASN.1 objects for Signature algorithm and Hash"); 242 } 243 } 244 245 /** 246 * Verify received signature in an inbound IKE packet. 247 * 248 * <p>Since IKE library is always a client, inbound IkeAuthDigitalSignPayload always signs IKE 249 * responder's SignedOctets, which is concatenation of the IKE_INIT response message, the Nonce 250 * of IKE initiator and the signed ID-Responder payload body. 251 * 252 * @param certificate received end certificate to verify the signature. 253 * @param ikeInitBytes IKE_INIT response for calculating IKE responder's SignedOctets. 254 * @param nonce nonce of IKE initiator for calculating IKE responder's SignedOctets. 255 * @param idPayloadBodyBytes ID-Responder payload body for calculating IKE responder's 256 * SignedOctets. 257 * @param ikePrf the negotiated PRF. 258 * @param prfKeyBytes the negotiated PRF responder key. 259 * @throws AuthenticationFailedException if received signature verification failed. 260 */ verifyInboundSignature( X509Certificate certificate, byte[] ikeInitBytes, byte[] nonce, byte[] idPayloadBodyBytes, IkeMacPrf ikePrf, byte[] prfKeyBytes)261 public void verifyInboundSignature( 262 X509Certificate certificate, 263 byte[] ikeInitBytes, 264 byte[] nonce, 265 byte[] idPayloadBodyBytes, 266 IkeMacPrf ikePrf, 267 byte[] prfKeyBytes) 268 throws AuthenticationFailedException { 269 byte[] dataToSignBytes = 270 getSignedOctets(ikeInitBytes, nonce, idPayloadBodyBytes, ikePrf, prfKeyBytes); 271 272 try { 273 Signature signValidator = Signature.getInstance(signatureAndHashAlgos); 274 signValidator.initVerify(certificate); 275 signValidator.update(dataToSignBytes); 276 277 if (!signValidator.verify(signature)) { 278 throw new AuthenticationFailedException("Signature verification failed."); 279 } 280 } catch (SignatureException | InvalidKeyException e) { 281 throw new AuthenticationFailedException(e); 282 } catch (NoSuchAlgorithmException e) { 283 throw new ProviderException( 284 "Security Provider does not support " + signatureAndHashAlgos); 285 } 286 } 287 288 @Override encodeAuthDataToByteBuffer(ByteBuffer byteBuffer)289 protected void encodeAuthDataToByteBuffer(ByteBuffer byteBuffer) { 290 if (authMethod == AUTH_METHOD_GENERIC_DIGITAL_SIGN) { 291 byteBuffer.put(SIGNATURE_ALGO_ASN1_BYTES_LEN); 292 byteBuffer.put(javaStandardSignAlgoNameToAsn1Bytes(signatureAndHashAlgos)); 293 } 294 byteBuffer.put(signature); 295 } 296 297 @Override getAuthDataLength()298 protected int getAuthDataLength() { 299 if (authMethod == AUTH_METHOD_GENERIC_DIGITAL_SIGN) { 300 return SIGNATURE_ALGO_ASN1_BYTES_LEN_LEN 301 + SIGNATURE_ALGO_ASN1_BYTES_LEN 302 + signature.length; 303 } 304 return signature.length; 305 } 306 307 @Override getTypeString()308 public String getTypeString() { 309 return "Auth(Digital Sign)"; 310 } 311 312 /** 313 * Gets the Signature Hash Algorithsm from the specified IkeNotifyPayload. 314 * 315 * @param notifyPayload IkeNotifyPayload to read serialized Signature Hash Algorithms from. The 316 * payload type must be SIGNATURE_HASH_ALGORITHMS. 317 * @return Set<Short> the Signature Hash Algorithms included in the notifyPayload. 318 * @throws InvalidSyntaxException if the included Signature Hash Algorithms are not serialized 319 * correctly 320 */ getSignatureHashAlgorithmsFromIkeNotifyPayload( IkeNotifyPayload notifyPayload)321 public static Set<Short> getSignatureHashAlgorithmsFromIkeNotifyPayload( 322 IkeNotifyPayload notifyPayload) throws InvalidSyntaxException { 323 if (notifyPayload.notifyType != IkeNotifyPayload.NOTIFY_TYPE_SIGNATURE_HASH_ALGORITHMS) { 324 throw new IllegalArgumentException( 325 "Notify payload type must be SIGNATURE_HASH_ALGORITHMS"); 326 } 327 328 // Hash Algorithm Identifiers are encoded as 16-bit values with no padding (RFC 7427#4) 329 int dataLen = notifyPayload.notifyData.length; 330 if (dataLen % 2 != 0) { 331 throw new InvalidSyntaxException( 332 "Received notify(SIGNATURE_HASH_ALGORITHMS) with invalid notify data"); 333 } 334 335 Set<Short> hashAlgos = new ArraySet<>(); 336 ByteBuffer serializedHashAlgos = ByteBuffer.wrap(notifyPayload.notifyData); 337 while (serializedHashAlgos.hasRemaining()) { 338 short hashAlgo = serializedHashAlgos.getShort(); 339 if (!ALL_SIGNATURE_ALGO_TYPES_SET.contains(hashAlgo) || !hashAlgos.add(hashAlgo)) { 340 getIkeLog().w(TAG, "Unexpected or repeated Signature Hash Algorithm: " + hashAlgo); 341 } 342 } 343 344 return hashAlgos; 345 } 346 } 347