Bug 1508730 - Add `WebResponse#certificate` r=geckoview-reviewers,droeh,agi

This is the server certificate, if any, as a
java.security.cert.X509Certificate.

Differential Revision: https://phabricator.services.mozilla.com/D58156

--HG--
extra : moz-landing-system : lando
This commit is contained in:
James Willcox 2020-01-10 15:09:24 +00:00
Родитель 4764fe7733
Коммит e2656f7f99
5 изменённых файлов: 72 добавлений и 1 удалений

Просмотреть файл

@ -1718,6 +1718,7 @@ package org.mozilla.geckoview {
method public void setReadTimeoutMillis(long);
field public static final long DEFAULT_READ_TIMEOUT_MS = 30000L;
field @Nullable public final InputStream body;
field @Nullable public final X509Certificate certificate;
field public final boolean isSecure;
field public final boolean redirected;
field public final int statusCode;
@ -1727,6 +1728,7 @@ package org.mozilla.geckoview {
ctor public Builder(@NonNull String);
method @NonNull public WebResponse.Builder body(@NonNull InputStream);
method @NonNull public WebResponse build();
method @NonNull public WebResponse.Builder certificate(@NonNull X509Certificate);
method @NonNull public WebResponse.Builder isSecure(boolean);
method @NonNull public WebResponse.Builder redirected(boolean);
method @NonNull public WebResponse.Builder statusCode(int);

Просмотреть файл

@ -204,6 +204,23 @@ class WebExecutorTest {
val response = fetch(WebRequest("https://example.com"))
assertThat("Status should match", response.statusCode, equalTo(200))
assertThat("isSecure should match", response.isSecure, equalTo(true))
val expectedSubject = if (env.isAutomation)
"CN=example.com"
else
"CN=www.example.org,OU=Technology,O=Internet Corporation for Assigned Names and Numbers,L=Los Angeles,ST=California,C=US"
val expectedIssuer = if (env.isAutomation)
"OU=Profile Guided Optimization,O=Mozilla Testing,CN=Temporary Certificate Authority"
else
"CN=DigiCert SHA2 Secure Server CA,O=DigiCert Inc,C=US"
assertThat("Subject should match",
response.certificate?.subjectX500Principal?.name,
equalTo(expectedSubject))
assertThat("Issuer should match",
response.certificate?.issuerX500Principal?.name,
equalTo(expectedIssuer))
}
@Test

Просмотреть файл

@ -12,7 +12,11 @@ import android.support.annotation.AnyThread;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
/**
* WebResponse represents an HTTP[S] response. It is normally created
@ -42,6 +46,11 @@ public class WebResponse extends WebMessage {
*/
public final boolean isSecure;
/**
* The server certificate used with this response, if any.
*/
public final @Nullable X509Certificate certificate;
/**
* An {@link InputStream} containing the response body, if available.
*/
@ -53,6 +62,7 @@ public class WebResponse extends WebMessage {
this.redirected = builder.mRedirected;
this.body = builder.mBody;
this.isSecure = builder.mIsSecure;
this.certificate = builder.mCertificate;
this.setReadTimeoutMillis(DEFAULT_READ_TIMEOUT_MS);
}
@ -81,6 +91,7 @@ public class WebResponse extends WebMessage {
/* package */ boolean mRedirected;
/* package */ InputStream mBody;
/* package */ boolean mIsSecure;
/* package */ X509Certificate mCertificate;
/**
* Constructs a new Builder instance with the specified URI.
@ -129,6 +140,29 @@ public class WebResponse extends WebMessage {
return this;
}
/**
* @param certificate The certificate used.
* @return This Builder instance.
*/
public @NonNull Builder certificate(final @NonNull X509Certificate certificate) {
mCertificate = certificate;
return this;
}
/**
* @param encodedCert The certificate used, encoded via DER. Only used via JNI.
*/
@WrapForJNI(exceptionMode = "nsresult")
private void certificateBytes(final @NonNull byte[] encodedCert) {
try {
final CertificateFactory factory = CertificateFactory.getInstance("X.509");
final X509Certificate cert = (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(encodedCert));
certificate(cert);
} catch (CertificateException e) {
throw new IllegalArgumentException("Unable to parse DER certificate");
}
}
/**
* Set the HTTP status code, e.g. 200.
*

Просмотреть файл

@ -23,11 +23,15 @@ exclude: true
- Added ['WebResponse#isSecure'][74.4], which indicates whether or not the response was
delivered over a secure connection.
([bug 1508730]({{bugzilla}}1508730))
- Added ['WebResponse#certificate'][74.5], which is the server certificate used for the
response, if any.
([bug 1508730]({{bugzilla}}1508730))
[74.1]: {{javadoc_uri}}/WebExtensionController.html#enable-org.mozilla.geckoview.WebExtension-int-
[74.2]: {{javadoc_uri}}/WebExtensionController.html#disable-org.mozilla.geckoview.WebExtension-int-
[74.3]: {{javadoc_uri}}/GeckoSession.ProgressDelegate.SecurityInformation.html#certificate
[74.4]: {{javadoc_uri}}/WebResponse.html#isSecure
[74.5]: {{javadoc_uri}}/WebResponse.html#certificate
## v73
- Added [`WebExtensionController.install`][73.1] and [`uninstall`][73.2] to
@ -538,4 +542,4 @@ exclude: true
[65.24]: {{javadoc_uri}}/CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String-
[65.25]: {{javadoc_uri}}/GeckoResult.html
[api-version]: 2fec52a2adbf657d6fddeaa16a6de69230eff42e
[api-version]: 749a613b61fc15e6c71787534e249ae3ca98ace3

Просмотреть файл

@ -17,6 +17,7 @@
#include "nsITransportSecurityInfo.h"
#include "nsIUploadChannel2.h"
#include "nsIWebProgressListener.h"
#include "nsIX509Cert.h"
#include "nsIDNSService.h"
#include "nsIDNSListener.h"
@ -334,6 +335,19 @@ class LoaderListener final : public nsIStreamListener,
uint32_t securityState = 0;
tsi->GetSecurityState(&securityState);
builder->IsSecure(securityState == nsIWebProgressListener::STATE_IS_SECURE);
nsCOMPtr<nsIX509Cert> cert;
tsi->GetServerCert(getter_AddRefs(cert));
if (cert) {
nsTArray<uint8_t> derBytes;
rv = cert->GetRawDER(derBytes);
NS_ENSURE_SUCCESS(rv, rv);
auto bytes = jni::ByteArray::New(
reinterpret_cast<const int8_t*>(derBytes.Elements()), derBytes.Length());
rv = builder->CertificateBytes(bytes);
NS_ENSURE_SUCCESS(rv, rv);
}
}
mResult->Complete(builder->Build());