Always include UUID in UD certificate (#300)

This commit is contained in:
Ehren Kret 2020-12-01 08:56:55 -06:00 committed by GitHub
parent b1160af896
commit 299b680013
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 15 additions and 48 deletions

View File

@ -33,25 +33,18 @@ public class CertificateGenerator {
this.serverCertificate = ServerCertificate.parseFrom(serverCertificate); this.serverCertificate = ServerCertificate.parseFrom(serverCertificate);
} }
public byte[] createFor(Account account, Device device, boolean includeE164, boolean includeUuid) throws IOException, InvalidKeyException { public byte[] createFor(Account account, Device device, boolean includeE164) throws IOException, InvalidKeyException {
SenderCertificate.Certificate.Builder builder = SenderCertificate.Certificate.newBuilder() SenderCertificate.Certificate.Builder builder = SenderCertificate.Certificate.newBuilder()
.setSenderDevice(Math.toIntExact(device.getId())) .setSenderDevice(Math.toIntExact(device.getId()))
.setExpires(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(expiresDays)) .setExpires(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(expiresDays))
.setIdentityKey(ByteString.copyFrom(Base64.decode(account.getIdentityKey()))) .setIdentityKey(ByteString.copyFrom(Base64.decode(account.getIdentityKey())))
.setSigner(serverCertificate); .setSigner(serverCertificate)
.setSenderUuid(account.getUuid().toString());
if (!includeE164 && !includeUuid) {
throw new IllegalArgumentException("Certificates must include one of a sender phone number or UUID");
}
if (includeE164) { if (includeE164) {
builder.setSender(account.getNumber()); builder.setSender(account.getNumber());
} }
if (includeUuid) {
builder.setSenderUuid(account.getUuid().toString());
}
byte[] certificate = builder.build().toByteArray(); byte[] certificate = builder.build().toByteArray();
byte[] signature = Curve.calculateSignature(privateKey, certificate); byte[] signature = Curve.calculateSignature(privateKey, certificate);

View File

@ -6,6 +6,7 @@
package org.whispersystems.textsecuregcm.controllers; package org.whispersystems.textsecuregcm.controllers;
import com.codahale.metrics.annotation.Timed; import com.codahale.metrics.annotation.Timed;
import io.dropwizard.auth.Auth;
import org.signal.zkgroup.auth.ServerZkAuthOperations; import org.signal.zkgroup.auth.ServerZkAuthOperations;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -29,8 +30,6 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import io.dropwizard.auth.Auth;
@SuppressWarnings("OptionalUsedAsFieldOrParameterType") @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@Path("/v1/certificate") @Path("/v1/certificate")
public class CertificateController { public class CertificateController {
@ -52,24 +51,17 @@ public class CertificateController {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Path("/delivery") @Path("/delivery")
public DeliveryCertificate getDeliveryCertificate(@Auth Account account, public DeliveryCertificate getDeliveryCertificate(@Auth Account account,
@QueryParam("includeE164") Optional<Boolean> includeE164, @QueryParam("includeE164") Optional<Boolean> includeE164)
@QueryParam("includeUuid") Optional<Boolean> includeUuid)
throws IOException, InvalidKeyException throws IOException, InvalidKeyException
{ {
if (!account.getAuthenticatedDevice().isPresent()) throw new AssertionError(); if (account.getAuthenticatedDevice().isEmpty()) {
throw new AssertionError();
}
if (Util.isEmpty(account.getIdentityKey())) { if (Util.isEmpty(account.getIdentityKey())) {
throw new WebApplicationException(Response.Status.BAD_REQUEST); throw new WebApplicationException(Response.Status.BAD_REQUEST);
} }
final boolean effectiveIncludeE164 = includeE164.orElse(true); return new DeliveryCertificate(certificateGenerator.createFor(account, account.getAuthenticatedDevice().get(), includeE164.orElse(true)));
final boolean effectiveIncludeUuid = includeUuid.orElse(false);
if (!effectiveIncludeE164 && !effectiveIncludeUuid) {
throw new WebApplicationException(Response.Status.BAD_REQUEST);
}
return new DeliveryCertificate(certificateGenerator.createFor(account, account.getAuthenticatedDevice().get(), effectiveIncludeE164, effectiveIncludeUuid));
} }
@Timed @Timed

View File

@ -15,7 +15,6 @@ import java.io.IOException;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.util.UUID; import java.util.UUID;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -37,10 +36,7 @@ public class CertificateGeneratorTest {
when(account.getNumber()).thenReturn("+18005551234"); when(account.getNumber()).thenReturn("+18005551234");
when(device.getId()).thenReturn(4L); when(device.getId()).thenReturn(4L);
assertTrue(certificateGenerator.createFor(account, device, true, true).length > 0); assertTrue(certificateGenerator.createFor(account, device, true).length > 0);
assertTrue(certificateGenerator.createFor(account, device, false, true).length > 0); assertTrue(certificateGenerator.createFor(account, device, false).length > 0);
assertTrue(certificateGenerator.createFor(account, device, true, false).length > 0);
assertThrows(IllegalArgumentException.class, () -> certificateGenerator.createFor(account, device, false, false));
} }
} }

View File

@ -6,6 +6,8 @@
package org.whispersystems.textsecuregcm.tests.controllers; package org.whispersystems.textsecuregcm.tests.controllers;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
import io.dropwizard.testing.junit.ResourceTestRule;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory; import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
import org.junit.ClassRule; import org.junit.ClassRule;
@ -36,13 +38,9 @@ import javax.ws.rs.core.Response;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
import io.dropwizard.testing.junit.ResourceTestRule;
import static junit.framework.TestCase.assertTrue; import static junit.framework.TestCase.assertTrue;
import static org.assertj.core.api.Java6Assertions.assertThat; import static org.assertj.core.api.Java6Assertions.assertThat;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
public class CertificateControllerTest { public class CertificateControllerTest {
@ -95,7 +93,8 @@ public class CertificateControllerTest {
assertEquals(certificate.getSender(), AuthHelper.VALID_NUMBER); assertEquals(certificate.getSender(), AuthHelper.VALID_NUMBER);
assertEquals(certificate.getSenderDevice(), 1L); assertEquals(certificate.getSenderDevice(), 1L);
assertFalse(certificate.hasSenderUuid()); assertTrue(certificate.hasSenderUuid());
assertEquals(AuthHelper.VALID_UUID.toString(), certificate.getSenderUuid());
assertTrue(Arrays.equals(certificate.getIdentityKey().toByteArray(), Base64.decode(AuthHelper.VALID_IDENTITY))); assertTrue(Arrays.equals(certificate.getIdentityKey().toByteArray(), Base64.decode(AuthHelper.VALID_IDENTITY)));
} }
@ -150,19 +149,6 @@ public class CertificateControllerTest {
assertTrue(Arrays.equals(certificate.getIdentityKey().toByteArray(), Base64.decode(AuthHelper.VALID_IDENTITY))); assertTrue(Arrays.equals(certificate.getIdentityKey().toByteArray(), Base64.decode(AuthHelper.VALID_IDENTITY)));
} }
@Test
public void testValidCertificateWithNoUuidNoE164() throws Exception {
Response response = resources.getJerseyTest()
.target("/v1/certificate/delivery")
.queryParam("includeUuid", "false")
.queryParam("includeE164", "false")
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get();
assertEquals(response.getStatus(), 400);
}
@Test @Test
public void testBadAuthentication() throws Exception { public void testBadAuthentication() throws Exception {
Response response = resources.getJerseyTest() Response response = resources.getJerseyTest()