Skip to content

Commit

Permalink
feat(FirstPartyEndpoint): Issue authorisation from ThirdPartyEndpoint…
Browse files Browse the repository at this point in the history
… instance
  • Loading branch information
gnarea committed Mar 10, 2021
1 parent 1aaa965 commit 80ae3ae
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package tech.relaycorp.relaydroid

/**
* Base class for all exceptions in this library.
*/
public abstract class RelaydroidException(message: String, cause: Throwable? = null) :
Exception(message, cause)
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import tech.relaycorp.relaynet.wrappers.x509.CertificateException
import java.security.KeyPair
import java.security.PublicKey
import java.time.ZonedDateTime
import tech.relaycorp.relaydroid.RelaydroidException
import tech.relaycorp.relaynet.wrappers.KeyException
import tech.relaycorp.relaynet.wrappers.deserializeRSAPublicKey

public class FirstPartyEndpoint
internal constructor(
Expand All @@ -25,18 +28,46 @@ internal constructor(

public val publicKey: PublicKey get() = keyPair.public

internal val pdaChain: List<Certificate> get() = listOf(identityCertificate, gatewayCertificate)

@Throws(CertificateException::class)
public fun issueAuthorization(
thirdPartyEndpoint: PublicThirdPartyEndpoint,
expiryDate: ZonedDateTime
): AuthorizationBundle {
return issueAuthorization(
thirdPartyEndpoint.identityCertificate.subjectPublicKey,
expiryDate
)
}

@Throws(CertificateException::class)
public fun issueAuthorization(
privateThirdPartyPublicKey: PublicKey,
thirdPartyEndpointPublicKeySerialized: ByteArray,
expiryDate: ZonedDateTime
): AuthorizationBundle {
val thirdPartyEndpointPublicKey = try {
thirdPartyEndpointPublicKeySerialized.deserializeRSAPublicKey()
} catch (exc: KeyException) {
throw AuthorizationIssuanceException(
"PDA grantee public key is not a valid RSA public key",
exc
)
}
return issueAuthorization(thirdPartyEndpointPublicKey, expiryDate)
}

@Throws(CertificateException::class)
private fun issueAuthorization(
thirdPartyEndpointPublicKey: PublicKey,
expiryDate: ZonedDateTime
): AuthorizationBundle {
val pda = issueDeliveryAuthorization(
subjectPublicKey = privateThirdPartyPublicKey,
subjectPublicKey = thirdPartyEndpointPublicKey,
issuerPrivateKey = keyPair.private,
validityEndDate = expiryDate,
issuerCertificate = identityCertificate
)
val pdaChain = listOf(identityCertificate, gatewayCertificate)
return AuthorizationBundle(
pda.serialize(),
pdaChain.map { it.serialize() }
Expand Down Expand Up @@ -90,3 +121,6 @@ internal constructor(
}
}
}

public class AuthorizationIssuanceException(message: String, cause: Throwable) :
RelaydroidException(message, cause)
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import tech.relaycorp.relaydroid.RegistrationFailedException
import tech.relaycorp.relaydroid.Relaynet
import tech.relaycorp.relaydroid.storage.mockStorage
import tech.relaycorp.relaydroid.test.FirstPartyEndpointFactory
import tech.relaycorp.relaydroid.test.ThirdPartyEndpointFactory
import tech.relaycorp.relaydroid.test.assertSameDateTime
import tech.relaycorp.relaynet.messages.control.PrivateNodeRegistration
import tech.relaycorp.relaynet.testing.pki.KeyPairSet
Expand Down Expand Up @@ -55,6 +56,14 @@ internal class FirstPartyEndpointTest {
assertEquals(endpoint.keyPair.public, endpoint.publicKey)
}

@Test
fun pdaChain() {
val endpoint = FirstPartyEndpointFactory.build()

assertTrue(endpoint.identityCertificate in endpoint.pdaChain)
assertTrue(PDACertPath.PRIVATE_GW in endpoint.pdaChain)
}

@Test
fun register() = runBlockingTest {
whenever(gateway.registerEndpoint(any())).thenReturn(PrivateNodeRegistration(
Expand Down Expand Up @@ -118,37 +127,64 @@ internal class FirstPartyEndpointTest {
}

@Test
fun issueAuthorization() {
val endpoint = FirstPartyEndpointFactory.build()
fun issueAuthorization_thirdPartyEndpoint() {
val firstPartyEndpoint = FirstPartyEndpointFactory.build()
val thirdPartyEndpoint = ThirdPartyEndpointFactory.buildPublic()
val expiryDate = ZonedDateTime.now().plusDays(1)

val authorization = firstPartyEndpoint.issueAuthorization(thirdPartyEndpoint, expiryDate)

validateAuthorization(authorization, firstPartyEndpoint, expiryDate)
}

@Test
fun issueAuthorization_publicKey_valid() {
val firstPartyEndpoint = FirstPartyEndpointFactory.build()
val expiryDate = ZonedDateTime.now().plusDays(1)

val authorization = endpoint.issueAuthorization(
KeyPairSet.PDA_GRANTEE.public,
val authorization = firstPartyEndpoint.issueAuthorization(
KeyPairSet.PDA_GRANTEE.public.encoded,
expiryDate
)

// PDA
val pda = Certificate.deserialize(authorization.pdaSerialized)
assertEquals(
KeyPairSet.PDA_GRANTEE.public.encoded.asList(),
pda.subjectPublicKey.encoded.asList()
)
assertEquals(
2,
pda.getCertificationPath(emptyList(), listOf(PDACertPath.PRIVATE_ENDPOINT)).size
)
assertSameDateTime(
expiryDate,
pda.expiryDate
)
validateAuthorization(authorization, firstPartyEndpoint, expiryDate)
}

// PDA chain
val pdaChainSerialized = authorization.pdaChainSerialized.map { it.asList() }
assertTrue(
pdaChainSerialized.contains(PDACertPath.PRIVATE_ENDPOINT.serialize().asList())
)
assertTrue(
pdaChainSerialized.contains(PDACertPath.PRIVATE_GW.serialize().asList())
@Test(expected = AuthorizationIssuanceException::class)
fun issueAuthorization_publicKey_invalid() {
val firstPartyEndpoint = FirstPartyEndpointFactory.build()
val expiryDate = ZonedDateTime.now().plusDays(1)

firstPartyEndpoint.issueAuthorization(
"This is not a public key".toByteArray(),
expiryDate
)
}
}

private fun validateAuthorization(
authorization: AuthorizationBundle,
firstPartyEndpoint: FirstPartyEndpoint,
expiryDate: ZonedDateTime
) {
// PDA
val pda = Certificate.deserialize(authorization.pdaSerialized)
assertEquals(
KeyPairSet.PDA_GRANTEE.public.encoded.asList(),
pda.subjectPublicKey.encoded.asList()
)
assertEquals(
2,
pda.getCertificationPath(emptyList(), listOf(PDACertPath.PRIVATE_ENDPOINT)).size
)
assertSameDateTime(
expiryDate,
pda.expiryDate
)

// PDA chain
assertEquals(
firstPartyEndpoint.pdaChain.map { it.serialize().asList() },
authorization.pdaChainSerialized.map { it.asList() }
)
}

0 comments on commit 80ae3ae

Please sign in to comment.