From b1d11d4f6982c02dc4ef3d727a900ea3a6a69545 Mon Sep 17 00:00:00 2001 From: Jon Chambers Date: Mon, 4 May 2020 16:48:49 -0400 Subject: [PATCH] Use APNs signing keys instead of expiring certificates. --- service/config/sample.yml | 6 +++-- .../configuration/ApnConfiguration.java | 20 +++++++++----- .../textsecuregcm/push/APNSender.java | 9 ++++--- .../push/RetryingApnsClient.java | 27 +++++-------------- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/service/config/sample.yml b/service/config/sample.yml index 81fc9789..dc949644 100644 --- a/service/config/sample.yml +++ b/service/config/sample.yml @@ -82,9 +82,11 @@ database: # Postgresql database configuration url: apn: # Apple Push Notifications configuration + sandbox: true bundleId: - pushCertificate: - pushKey: + keyId: + teamId: + signingKey: gcm: # GCM Configuration senderId: diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/configuration/ApnConfiguration.java b/service/src/main/java/org/whispersystems/textsecuregcm/configuration/ApnConfiguration.java index 82a8ebf9..31250602 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/configuration/ApnConfiguration.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/configuration/ApnConfiguration.java @@ -24,11 +24,15 @@ public class ApnConfiguration { @NotEmpty @JsonProperty - private String pushCertificate; + private String teamId; @NotEmpty @JsonProperty - private String pushKey; + private String keyId; + + @NotEmpty + @JsonProperty + private String signingKey; @NotEmpty @JsonProperty @@ -37,12 +41,16 @@ public class ApnConfiguration { @JsonProperty private boolean sandbox = false; - public String getPushCertificate() { - return pushCertificate; + public String getTeamId() { + return teamId; } - public String getPushKey() { - return pushKey; + public String getKeyId() { + return keyId; + } + + public String getSigningKey() { + return signingKey; } public String getBundleId() { diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/push/APNSender.java b/service/src/main/java/org/whispersystems/textsecuregcm/push/APNSender.java index e71bd04a..4cbdff17 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/push/APNSender.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/push/APNSender.java @@ -35,6 +35,8 @@ import org.whispersystems.textsecuregcm.util.Constants; import javax.annotation.Nullable; import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; import java.util.Date; import java.util.Optional; import java.util.concurrent.ExecutorService; @@ -61,13 +63,14 @@ public class APNSender implements Managed { private final RetryingApnsClient apnsClient; public APNSender(AccountsManager accountsManager, ApnConfiguration configuration) - throws IOException + throws IOException, NoSuchAlgorithmException, InvalidKeyException { this.accountsManager = accountsManager; this.bundleId = configuration.getBundleId(); this.sandbox = configuration.isSandboxEnabled(); - this.apnsClient = new RetryingApnsClient(configuration.getPushCertificate(), - configuration.getPushKey(), + this.apnsClient = new RetryingApnsClient(configuration.getSigningKey(), + configuration.getTeamId(), + configuration.getKeyId(), sandbox); } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/push/RetryingApnsClient.java b/service/src/main/java/org/whispersystems/textsecuregcm/push/RetryingApnsClient.java index 7eab8c3a..fa65588f 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/push/RetryingApnsClient.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/push/RetryingApnsClient.java @@ -7,28 +7,26 @@ import com.eatthepath.pushy.apns.ApnsClient; import com.eatthepath.pushy.apns.ApnsClientBuilder; import com.eatthepath.pushy.apns.DeliveryPriority; import com.eatthepath.pushy.apns.PushNotificationResponse; +import com.eatthepath.pushy.apns.auth.ApnsSigningKey; import com.eatthepath.pushy.apns.metrics.dropwizard.DropwizardApnsClientMetricsListener; import com.eatthepath.pushy.apns.util.SimpleApnsPushNotification; import com.google.common.annotations.VisibleForTesting; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; -import org.bouncycastle.openssl.PEMReader; +import io.netty.util.concurrent.GenericFutureListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.whispersystems.textsecuregcm.util.Constants; import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.InputStreamReader; -import java.security.KeyPair; -import java.security.PrivateKey; -import java.security.cert.X509Certificate; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; import java.util.Date; import java.util.Map; import java.util.concurrent.ExecutionException; import static com.codahale.metrics.MetricRegistry.name; -import io.netty.util.concurrent.GenericFutureListener; public class RetryingApnsClient { @@ -36,8 +34,8 @@ public class RetryingApnsClient { private final ApnsClient apnsClient; - RetryingApnsClient(String apnCertificate, String apnKey, boolean sandbox) - throws IOException + RetryingApnsClient(String apnSigningKey, String teamId, String keyId, boolean sandbox) + throws IOException, InvalidKeyException, NoSuchAlgorithmException { MetricRegistry metricRegistry = SharedMetricRegistries.getOrCreate(Constants.METRICS_NAME); DropwizardApnsClientMetricsListener metricsListener = new DropwizardApnsClientMetricsListener(); @@ -46,8 +44,7 @@ public class RetryingApnsClient { metricRegistry.register(name(getClass(), entry.getKey()), entry.getValue()); } - this.apnsClient = new ApnsClientBuilder().setClientCredentials(initializeCertificate(apnCertificate), - initializePrivateKey(apnKey), null) + this.apnsClient = new ApnsClientBuilder().setSigningKey(ApnsSigningKey.loadFromInputStream(new ByteArrayInputStream(apnSigningKey.getBytes()), teamId, keyId)) .setMetricsListener(metricsListener) .setApnsServer(sandbox ? ApnsClientBuilder.DEVELOPMENT_APNS_HOST : ApnsClientBuilder.PRODUCTION_APNS_HOST) .build(); @@ -71,16 +68,6 @@ public class RetryingApnsClient { apnsClient.close(); } - private static X509Certificate initializeCertificate(String pemCertificate) throws IOException { - PEMReader reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(pemCertificate.getBytes()))); - return (X509Certificate) reader.readObject(); - } - - private static PrivateKey initializePrivateKey(String pemKey) throws IOException { - PEMReader reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(pemKey.getBytes()))); - return ((KeyPair) reader.readObject()).getPrivate(); - } - private static final class ResponseHandler implements GenericFutureListener>> { private final SettableFuture future;