Chromium Code Reviews| Index: components/cronet/android/api/src/org/chromium/net/CronetEngine.java |
| diff --git a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java |
| index 29fd3f01b0f285697e89737f794787092f4dc0a5..1c2543cf2f37940eb0d61bbd29bca41586e676c7 100644 |
| --- a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java |
| +++ b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java |
| @@ -6,6 +6,7 @@ package org.chromium.net; |
| import android.content.Context; |
| import android.support.annotation.IntDef; |
| +import android.util.Base64; |
| import android.util.Log; |
| import org.json.JSONArray; |
| @@ -20,8 +21,12 @@ import java.net.Proxy; |
| import java.net.URL; |
| import java.net.URLConnection; |
| import java.net.URLStreamHandlerFactory; |
| +import java.util.Collection; |
| +import java.util.Date; |
| +import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| +import java.util.Set; |
| import java.util.concurrent.Executor; |
| /** |
| @@ -301,6 +306,77 @@ public abstract class CronetEngine { |
| } |
| /** |
| + * Adds public key pinning for a given host. |
| + * |
| + * @param hostName name of the host to which public keys should be pinned. |
| + * @param pinsSha256 a collection of pins. Each pin is the SHA-256 cryptographic |
| + * hash of DER-encoded ASN.1 representation of Subject Public |
|
mef
2015/11/06 18:02:17
pinning -> pins
kapishnikov
2015/11/06 19:45:08
Done.
|
| + * Key Info (SPKI) of the host X.509 certificate. You can use |
|
mef
2015/11/06 18:02:16
Usually Chrome frowns upon use of 'you', 'we', etc
kapishnikov
2015/11/06 19:45:08
Done.
|
| + * {@code security.cert.X509Certificate.getPublicKey().getEncoded()} |
| + * to obtain DER-encoded ASN.1 representation of SPKI. |
| + * @param includeSubdomains indicates whether the pinning policy should be applied to |
| + * subdomains of {@code hostName}. |
| + * @param expirationDate specifies the expiration date for the pins. |
| + * @return the builder to facilitate chaining. |
| + * @throws NullPointerException if one of the input parameters is null. |
| + * @throws IllegalArgumentException if {@code pinsSha256} collection contains a byte array |
| + * that does not represent a valid SHA-256 hash. |
| + * |
| + */ |
| + public Builder addPublicKeyPins(String hostName, Collection<byte[]> pinsSha256, |
| + boolean includeSubdomains, Date expirationDate) { |
| + // Validate the input |
|
mef
2015/11/06 18:02:16
comments should end in period, but reasonably we d
kapishnikov
2015/11/06 19:45:08
Done.
|
| + if (hostName == null) { |
| + throw new NullPointerException("The hostname cannot be null"); |
| + } |
| + if (pinsSha256 == null) { |
| + throw new NullPointerException("The collection of SHA256 pins cannot be null"); |
| + } |
| + try { |
| + // Add HPKP_LIST JSON array element if it is not present. |
| + JSONArray hpkpList = mConfig.optJSONArray(CronetEngineBuilderList.HPKP_LIST); |
| + if (hpkpList == null) { |
| + hpkpList = new JSONArray(); |
| + mConfig.put(CronetEngineBuilderList.HPKP_LIST, hpkpList); |
| + } |
| + |
| + // Convert the pin to BASE64 encoding. |
| + Set<String> hashes = new HashSet<>(pinsSha256.size()); |
| + for (byte[] pinSha256 : pinsSha256) { |
| + hashes.add(convertSha256ToBase64WithPrefix(pinSha256)); |
| + } |
| + |
| + // Add new element to HPKP_LIST JSON array. |
| + JSONObject hpkp = new JSONObject(); |
| + hpkp.put(CronetEngineBuilderList.HPKP_HOST, hostName); |
| + hpkp.put(CronetEngineBuilderList.HPKP_PIN_HASHES, new JSONArray(hashes)); |
| + hpkp.put(CronetEngineBuilderList.HPKP_INCLUDE_SUBDOMAINS, includeSubdomains); |
| + // The expiration time is passed as a double, in seconds since January 1, 1970. |
| + hpkp.put(CronetEngineBuilderList.HPKP_EXPIRATION_DATE, |
| + (double) expirationDate.getTime() / 1000); |
|
mef
2015/11/06 18:02:16
why double? Can it be long?
kapishnikov
2015/11/06 19:45:08
Our current C++ JsonValueConverter (https://code.g
|
| + hpkpList.put(hpkp); |
| + } catch (JSONException e) { |
| + Log.e(TAG, "Unable to add public key pins", e); |
|
mef
2015/11/06 18:02:16
hrm, why wouldn't we re-throw it? The builder is w
kapishnikov
2015/11/06 19:45:08
I agree that re-throwing an exception would be the
|
| + } |
| + return this; |
| + } |
| + |
| + /** |
| + * Converts a given SHA256 array of bytes to BASE64 encoding with the prefix. The format |
| + * corresponds to the format that is expected by net::HashValue class. |
| + * |
| + * @param sha256 SHA256 bytes to convert to BASE64. |
| + * @return the BASE64 conversion. |
| + * @throws IllegalArgumentException if the provided pin is invalid. |
| + */ |
| + private String convertSha256ToBase64WithPrefix(byte[] sha256) { |
| + if (sha256 == null || sha256.length != 32) { |
| + throw new IllegalArgumentException("The provided pin is invalid"); |
|
mef
2015/11/06 18:02:16
provided -> public key
kapishnikov
2015/11/06 19:45:08
Done.
|
| + } |
| + return "sha256/" + Base64.encodeToString(sha256, Base64.NO_WRAP); |
| + } |
| + |
| + /** |
| * Sets experimental QUIC connection options, overwriting any pre-existing |
| * options. List of options is subject to change. |
| * |