Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit da2c0255 authored by Vincent Breitmoser's avatar Vincent Breitmoser
Browse files

add unit tests for key gossip

parent d8f9f2df
Loading
Loading
Loading
Loading
+96 −0
Original line number Diff line number Diff line
package com.fsck.k9.autocrypt


import com.fsck.k9.mail.filter.Base64
import com.fsck.k9.mailstore.MimePartStreamParser
import org.junit.Assert.*
import org.junit.Test


class AutocryptGossipHeaderParserTest {
    val GOSSIP_DATA_BOB = Base64.decodeBase64(
            """mQGNBFoBt74BDAC8AMsjPY17kxodbfmHah38ZQipY0yfuo97WUBs2jeiFYlQdunPANi5VMgbAX+H
     Mq1XoBRs6qW+WpX8Uj11mu22c57BTUXJRbRr4TnTuuOQmT0egwFDe3x8vHSFmcf9OzG8iKR9ftUE
     +F2ewrzzmm3XY8hy7QeUgBfClZVA6A3rsX4gGawjDo6ZRBbYwckINgGX/vQk6rGs""".toByteArray())

    val GOSSIP_HEADER_BOB = """addr=bob@autocrypt.example; keydata=
 mQGNBFoBt74BDAC8AMsjPY17kxodbfmHah38ZQipY0yfuo97WUBs2jeiFYlQdunPANi5VMgbAX+H
 Mq1XoBRs6qW+WpX8Uj11mu22c57BTUXJRbRr4TnTuuOQmT0egwFDe3x8vHSFmcf9OzG8iKR9ftUE
 +F2ewrzzmm3XY8hy7QeUgBfClZVA6A3rsX4gGawjDo6ZRBbYwckINgGX/vQk6rGs"""

    val GOSSIP_RAW_HEADER_BOB = "Autocrypt-Gossip: $GOSSIP_HEADER_BOB".replace("\n", "\r\n")

    // Example from Autocrypt 1.0 appendix
    val GOSSIP_PART = """Autocrypt-Gossip: $GOSSIP_HEADER_BOB
Autocrypt-Gossip: addr=carol@autocrypt.example; keydata=
 mQGNBFoBt8oBDADGqfZ6PqW05hUEO1dkKm+ixJXnbVriPz2tRkAqT7lTF4KBGitxo4IPv9RPIjJR
 UMUo89ddyqQfiwKxdFCMDqFDnVRWlDaM+r8sauNJoIFwtTFuvUpkFeCI5gYvneEIIbf1r3Xx1pf5
 Iy9qsd5eg/4Vvc2AezUv+A6p2DUNHgFMX2FfDus+EPO0wgeWbNaV601aE7UhyugB
Content-Type: text/plain

Hi Bob and Carol,

I wanted to introduce the two of you to each other.

I hope you are both doing well!  You can now both "reply all" here,
and the thread will remain encrypted.

Regards,
Alice
""".replace("\n", "\r\n")

    private val autocryptGossipHeaderParser = AutocryptGossipHeaderParser.getInstance()

    @Test
    fun parseFromPart() {
        val gossipPart = MimePartStreamParser.parse(null, GOSSIP_PART.byteInputStream())
        val allAutocryptGossipHeaders = autocryptGossipHeaderParser.getAllAutocryptGossipHeaders(gossipPart)

        assertEquals("text/plain", gossipPart.mimeType)
        assertEquals(2, allAutocryptGossipHeaders.size)
        assertEquals("bob@autocrypt.example", allAutocryptGossipHeaders[0].addr)
        assertEquals("carol@autocrypt.example", allAutocryptGossipHeaders[1].addr)
        assertArrayEquals(GOSSIP_DATA_BOB, allAutocryptGossipHeaders[0].keyData)
    }

    @Test
    fun parseString() {
        val gossipHeader = autocryptGossipHeaderParser.parseAutocryptGossipHeader(GOSSIP_HEADER_BOB)

        gossipHeader!!
        assertArrayEquals(GOSSIP_DATA_BOB, gossipHeader.keyData)
        assertEquals(GOSSIP_RAW_HEADER_BOB, gossipHeader.toRawHeaderString())
    }

    @Test
    fun parseHeader_missingKeydata() {
        val gossipHeader = autocryptGossipHeaderParser.parseAutocryptGossipHeader(
                "addr=CDEF")

        assertNull(gossipHeader)
    }

    @Test
    fun parseHeader_unknownCritical() {
        val gossipHeader = autocryptGossipHeaderParser.parseAutocryptGossipHeader(
                "addr=bawb; somecritical=value; keydata=aGk")

        assertNull(gossipHeader)
    }

    @Test
    fun parseHeader_unknownNonCritical() {
        val gossipHeader = autocryptGossipHeaderParser.parseAutocryptGossipHeader(
                "addr=bawb; _somenoncritical=value; keydata=aGk")

        assertNotNull(gossipHeader)
    }

    @Test
    fun parseHeader_brokenBase64() {
        val gossipHeader = autocryptGossipHeaderParser.parseAutocryptGossipHeader(
                "addr=bawb; _somenoncritical=value; keydata=X")

        assertNull(gossipHeader)
    }
}
 No newline at end of file
+60 −0
Original line number Diff line number Diff line
@@ -330,6 +330,66 @@ public class PgpMessageBuilderTest {
        verifyNoMoreInteractions(mockCallback);
    }

    @Test
    public void buildEncrypt__checkGossip() throws MessagingException {
        ComposeCryptoStatus cryptoStatus = cryptoStatusBuilder
                .setCryptoMode(CryptoMode.CHOICE_ENABLED)
                .setRecipients(Arrays.asList(
                        new Recipient("alice", "alice@example.org", "alice", -1, "key"),
                        new Recipient("bob", "bob@example.org", "bob", -1, "key2")))
                .build();
        pgpMessageBuilder.setCryptoStatus(cryptoStatus);

        Intent returnIntent = new Intent();
        returnIntent.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
        when(openPgpApi.executeApi(any(Intent.class), any(OpenPgpDataSource.class), any(OutputStream.class))).thenReturn(returnIntent);
        pgpMessageBuilder.buildAsync(mock(Callback.class));

        verify(autocryptOpenPgpApiInteractor).getKeyMaterialForUserId(same(openPgpApi), eq("alice@example.org"));
        verify(autocryptOpenPgpApiInteractor).getKeyMaterialForUserId(same(openPgpApi), eq("bob@example.org"));
    }

    @Test
    public void buildEncrypt__checkGossip__filterBcc() throws MessagingException {
        ComposeCryptoStatus cryptoStatus = cryptoStatusBuilder
                .setCryptoMode(CryptoMode.CHOICE_ENABLED)
                .setRecipients(Arrays.asList(
                        new Recipient("alice", "alice@example.org", "alice", -1, "key"),
                        new Recipient("bob", "bob@example.org", "bob", -1, "key2"),
                        new Recipient("carol", "carol@example.org", "carol", -1, "key3")))
                .build();
        pgpMessageBuilder.setCryptoStatus(cryptoStatus);
        pgpMessageBuilder.setBcc(Collections.singletonList(new Address("carol@example.org")));

        Intent returnIntent = new Intent();
        returnIntent.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
        when(openPgpApi.executeApi(any(Intent.class), any(OpenPgpDataSource.class), any(OutputStream.class))).thenReturn(returnIntent);
        pgpMessageBuilder.buildAsync(mock(Callback.class));

        verify(autocryptOpenPgpApiInteractor).getKeyMaterialForUserId(same(openPgpApi), eq("alice@example.org"));
        verify(autocryptOpenPgpApiInteractor).getKeyMaterialForUserId(same(openPgpApi), eq("bob@example.org"));
    }

    @Test
    public void buildEncrypt__checkGossip__filterBccSingleRecipient() throws MessagingException {
        ComposeCryptoStatus cryptoStatus = cryptoStatusBuilder
                .setCryptoMode(CryptoMode.CHOICE_ENABLED)
                .setRecipients(Arrays.asList(
                        new Recipient("alice", "alice@example.org", "alice", -1, "key"),
                        new Recipient("carol", "carol@example.org", "carol", -1, "key3")))
                .build();
        pgpMessageBuilder.setCryptoStatus(cryptoStatus);
        pgpMessageBuilder.setBcc(Collections.singletonList(new Address("carol@example.org")));

        Intent returnIntent = new Intent();
        returnIntent.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
        when(openPgpApi.executeApi(any(Intent.class), any(OpenPgpDataSource.class), any(OutputStream.class))).thenReturn(returnIntent);
        pgpMessageBuilder.buildAsync(mock(Callback.class));

        verify(autocryptOpenPgpApiInteractor).getKeyMaterialForKeyId(any(OpenPgpApi.class), any(Long.class), any(String.class));
        verifyNoMoreInteractions(autocryptOpenPgpApiInteractor);
    }

    @Test
    public void buildEncrypt__shouldSucceed() throws MessagingException {
        ComposeCryptoStatus cryptoStatus = cryptoStatusBuilder