Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Send message to private endpoint #59

Merged
merged 2 commits into from
Mar 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import tech.relaycorp.relaynet.issueDeliveryAuthorization
import tech.relaycorp.relaynet.wrappers.KeyException
import tech.relaycorp.relaynet.wrappers.deserializeRSAPublicKey
import tech.relaycorp.relaynet.wrappers.generateRSAKeyPair
import tech.relaycorp.relaynet.wrappers.privateAddress
import tech.relaycorp.relaynet.wrappers.x509.Certificate
import tech.relaycorp.relaynet.wrappers.x509.CertificateException

Expand Down Expand Up @@ -43,12 +42,11 @@ internal constructor(
public fun issueAuthorization(
thirdPartyEndpoint: ThirdPartyEndpoint,
expiryDate: ZonedDateTime
): AuthorizationBundle {
return issueAuthorization(
): AuthorizationBundle =
issueAuthorization(
thirdPartyEndpoint.identityCertificate.subjectPublicKey,
expiryDate
)
}

/**
* Issue a PDA for a third-party endpoint using its public key.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package tech.relaycorp.relaydroid.endpoint

import java.nio.ByteBuffer
import org.bson.BSONException
import org.bson.BsonBinary
import org.bson.BsonBinaryReader
import org.bson.BsonBinaryWriter
import org.bson.BsonType
import org.bson.io.BasicOutputBuffer
import tech.relaycorp.relaydroid.storage.persistence.PersistenceException
import tech.relaycorp.relaynet.wrappers.x509.Certificate

internal data class PrivateThirdPartyEndpointData(
val identityCertificate: Certificate,
val authBundle: AuthorizationBundle
) {
@Throws(PersistenceException::class)
fun serialize(): ByteArray =
try {
BasicOutputBuffer().use { output ->
BsonBinaryWriter(output).use { w ->
w.writeStartDocument()
w.writeBinaryData(
"identity_certificate",
BsonBinary(identityCertificate.serialize())
)
w.writeBinaryData("pda", BsonBinary(authBundle.pdaSerialized))
w.writeStartArray("pda_chain")
authBundle.pdaChainSerialized.forEach {
w.writeBinaryData(BsonBinary(it))
}
w.writeEndArray()
w.writeEndDocument()
}
output.toByteArray()
}
} catch (exp: BSONException) {
throw PersistenceException("Could not serialize PrivateThirdPartyEndpoint", exp)
}

companion object {
@Throws(PersistenceException::class)
fun deserialize(byteArray: ByteArray): PrivateThirdPartyEndpointData =
try {
BsonBinaryReader(ByteBuffer.wrap(byteArray)).use { r ->
r.readStartDocument()

val identityCertificate = Certificate.deserialize(
r.readBinaryData("identity_certificate").data
)
val pdaSerialized = r.readBinaryData("pda").data

val pdaChainSerialized = mutableListOf<ByteArray>()
r.readName("pda_chain")
r.readStartArray()
while (r.readBsonType() != BsonType.END_OF_DOCUMENT) {
pdaChainSerialized.add(r.readBinaryData().data)
}
r.readEndArray()

r.readEndDocument()
PrivateThirdPartyEndpointData(
identityCertificate,
AuthorizationBundle(pdaSerialized, pdaChainSerialized)
)
}
} catch (exp: BSONException) {
throw PersistenceException(
"Could not deserialize PrivateThirdPartyEndpoint",
exp
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package tech.relaycorp.relaydroid.endpoint

import java.nio.ByteBuffer
import org.bson.BSONException
import org.bson.BsonBinary
import org.bson.BsonBinaryReader
import org.bson.BsonBinaryWriter
import org.bson.io.BasicOutputBuffer
import tech.relaycorp.relaydroid.storage.persistence.PersistenceException
import tech.relaycorp.relaynet.wrappers.x509.Certificate

internal data class PublicThirdPartyEndpointData(
val publicAddress: String,
val identityCertificate: Certificate
) {
@Throws(PersistenceException::class)
fun serialize(): ByteArray =
try {
BasicOutputBuffer().use { output ->
BsonBinaryWriter(output).use { w ->
w.writeStartDocument()
w.writeString("public_address", publicAddress)
w.writeBinaryData(
"identity_certificate",
BsonBinary(identityCertificate.serialize())
)
w.writeEndDocument()
}
output.toByteArray()
}
} catch (exp: BSONException) {
throw PersistenceException("Could not serialize PublicThirdPartyEndpoint", exp)
}

companion object {
@Throws(PersistenceException::class)
fun deserialize(byteArray: ByteArray): PublicThirdPartyEndpointData =
try {
BsonBinaryReader(ByteBuffer.wrap(byteArray)).use { r ->
r.readStartDocument()
PublicThirdPartyEndpointData(
r.readString("public_address"),
Certificate.deserialize(
r.readBinaryData("identity_certificate").data
)
).also {
r.readEndDocument()
}
}
} catch (exp: BSONException) {
throw PersistenceException(
"Could not deserialize PublicThirdPartyEndpoint",
exp
)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
package tech.relaycorp.relaydroid.endpoint

import java.nio.ByteBuffer
import org.bson.BSONException
import org.bson.BsonBinary
import org.bson.BsonBinaryReader
import org.bson.BsonBinaryWriter
import org.bson.io.BasicOutputBuffer
import tech.relaycorp.relaydroid.RelaydroidException
import tech.relaycorp.relaydroid.Storage
import tech.relaycorp.relaydroid.storage.persistence.PersistenceException
Expand Down Expand Up @@ -37,8 +31,9 @@ public sealed class ThirdPartyEndpoint(
*/
public class PrivateThirdPartyEndpoint internal constructor(
public val firstPartyEndpointAddress: String,
identityCertificate: Certificate,
internal val pda: Certificate,
identityCertificate: Certificate
internal val pdaChain: List<Certificate>
) : ThirdPartyEndpoint(identityCertificate) {

override val address: String get() = privateAddress
Expand All @@ -53,10 +48,13 @@ public class PrivateThirdPartyEndpoint internal constructor(
firstPartyAddress: String
): PrivateThirdPartyEndpoint? {
val key = "${firstPartyAddress}_$thirdPartyAddress"
return Storage.thirdPartyAuthorization.get(key)?.let { auth ->
Storage.thirdPartyIdentityCertificate.get(key)?.let { id ->
PrivateThirdPartyEndpoint(firstPartyAddress, auth, id)
}
return Storage.privateThirdParty.get(key)?.let { data ->
PrivateThirdPartyEndpoint(
firstPartyAddress,
data.identityCertificate,
Certificate.deserialize(data.authBundle.pdaSerialized),
data.authBundle.pdaChainSerialized.map { Certificate.deserialize(it) }
)
}
}

Expand All @@ -69,9 +67,12 @@ public class PrivateThirdPartyEndpoint internal constructor(
InvalidAuthorizationException::class
)
public suspend fun import(
pda: Certificate,
identityCertificate: Certificate
identityCertificate: Certificate,
authBundle: AuthorizationBundle
): PrivateThirdPartyEndpoint {
val pda = Certificate.deserialize(authBundle.pdaSerialized)
val pdaChain = authBundle.pdaChainSerialized.map { Certificate.deserialize(it) }

val firstPartyAddress = pda.subjectPrivateAddress

Storage.identityCertificate.get(firstPartyAddress)
Expand All @@ -85,18 +86,20 @@ public class PrivateThirdPartyEndpoint internal constructor(
throw InvalidAuthorizationException("PDA is invalid", exc)
}
try {
pda.getCertificationPath(emptyList(), listOf(identityCertificate))
pda.getCertificationPath(emptyList(), pdaChain)
} catch (e: CertificateException) {
throw InvalidAuthorizationException("PDA was not issued by third-party endpoint", e)
}

val thirdPartyAddress = identityCertificate.subjectPrivateAddress

val key = "${firstPartyAddress}_$thirdPartyAddress"
Storage.thirdPartyAuthorization.set(key, pda)
Storage.thirdPartyIdentityCertificate.set(key, identityCertificate)
Storage.privateThirdParty.set(
key,
PrivateThirdPartyEndpointData(identityCertificate, authBundle)
)

return PrivateThirdPartyEndpoint(firstPartyAddress, pda, identityCertificate)
return PrivateThirdPartyEndpoint(firstPartyAddress, identityCertificate, pda, pdaChain)
}
}
}
Expand All @@ -119,7 +122,7 @@ public class PublicThirdPartyEndpoint internal constructor(
*/
@Throws(PersistenceException::class)
public suspend fun load(publicAddress: String): PublicThirdPartyEndpoint? =
Storage.publicThirdPartyCertificate.get(publicAddress)?.let {
Storage.publicThirdParty.get(publicAddress)?.let {
PublicThirdPartyEndpoint(it.publicAddress, it.identityCertificate)
}

Expand All @@ -143,60 +146,13 @@ public class PublicThirdPartyEndpoint internal constructor(
throw InvalidThirdPartyEndpoint("Invalid identity certificate")
}
val thirdPartyAddress = identityCertificate.subjectPrivateAddress
Storage.publicThirdPartyCertificate.set(
Storage.publicThirdParty.set(
thirdPartyAddress,
StoredData(publicAddress, identityCertificate)
PublicThirdPartyEndpointData(publicAddress, identityCertificate)
)
return PublicThirdPartyEndpoint(publicAddress, identityCertificate)
}
}

internal data class StoredData(
val publicAddress: String,
val identityCertificate: Certificate
) {
@Throws(PersistenceException::class)
fun serialize(): ByteArray {
try {
val output = BasicOutputBuffer()
BsonBinaryWriter(output).use {
it.writeStartDocument()
it.writeString("public_address", publicAddress)
it.writeBinaryData(
"identity_certificate",
BsonBinary(identityCertificate.serialize())
)
it.writeEndDocument()
}
return output.toByteArray()
} catch (exp: BSONException) {
throw PersistenceException("Could not serialize PublicThirdPartyEndpoint", exp)
}
}

companion object {
@Throws(PersistenceException::class)
fun deserialize(byteArray: ByteArray): StoredData =
try {
BsonBinaryReader(ByteBuffer.wrap(byteArray)).use { reader ->
reader.readStartDocument()
StoredData(
reader.readString("public_address"),
Certificate.deserialize(
reader.readBinaryData("identity_certificate").data
)
).also {
reader.readEndDocument()
}
}
} catch (exp: BSONException) {
throw PersistenceException(
"Could not deserialize PublicThirdPartyEndpoint",
exp
)
}
}
}
}

public class UnknownThirdPartyEndpointException(message: String) : RelaydroidException(message)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,32 +81,23 @@ private constructor(
)
}

private suspend fun getSenderCertificate() =
private fun getSenderCertificate(): Certificate =
when (recipientEndpoint) {
is PublicThirdPartyEndpoint ->
getSelfSignedSenderCertificate()
is PrivateThirdPartyEndpoint ->
getParcelDeliveryAuthorization(recipientEndpoint)
is PublicThirdPartyEndpoint -> getSelfSignedSenderCertificate()
is PrivateThirdPartyEndpoint -> recipientEndpoint.pda
}

private fun getSelfSignedSenderCertificate(): Certificate {
return issueEndpointCertificate(
private fun getSelfSignedSenderCertificate(): Certificate =
issueEndpointCertificate(
senderEndpoint.keyPair.public,
senderEndpoint.keyPair.private,
validityStartDate = parcelCreationDate,
validityEndDate = parcelExpiryDate
)
}

private suspend fun getParcelDeliveryAuthorization(
recipientEndpoint: PrivateThirdPartyEndpoint
): Certificate {
TODO("Not yet implemented")
}

private suspend fun getSenderCertificateChain(): Set<Certificate> =
private fun getSenderCertificateChain(): Set<Certificate> =
when (recipientEndpoint) {
is PublicThirdPartyEndpoint -> emptySet()
is PrivateThirdPartyEndpoint -> TODO("Include senderEndpoint.gatewayCertificate")
is PrivateThirdPartyEndpoint -> recipientEndpoint.pdaChain.toSet()
}
}
24 changes: 9 additions & 15 deletions lib/src/main/java/tech/relaycorp/relaydroid/storage/StorageImpl.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package tech.relaycorp.relaydroid.storage

import java.security.KeyPair
import tech.relaycorp.relaydroid.endpoint.PublicThirdPartyEndpoint
import tech.relaycorp.relaydroid.endpoint.PrivateThirdPartyEndpointData
import tech.relaycorp.relaydroid.endpoint.PublicThirdPartyEndpointData
import tech.relaycorp.relaydroid.storage.persistence.Persistence
import tech.relaycorp.relaydroid.storage.persistence.PersistenceException
import tech.relaycorp.relaynet.wrappers.deserializeRSAKeyPair
Expand Down Expand Up @@ -34,25 +35,18 @@ constructor(
deserializer = Certificate::deserialize
)

internal val publicThirdPartyCertificate: Module<PublicThirdPartyEndpoint.StoredData> = Module(
internal val publicThirdParty: Module<PublicThirdPartyEndpointData> = Module(
persistence = persistence,
prefix = "public_third_party_",
serializer = PublicThirdPartyEndpoint.StoredData::serialize,
deserializer = PublicThirdPartyEndpoint.StoredData::deserialize
serializer = PublicThirdPartyEndpointData::serialize,
deserializer = PublicThirdPartyEndpointData::deserialize
)

internal val thirdPartyAuthorization: Module<Certificate> = Module(
internal val privateThirdParty: Module<PrivateThirdPartyEndpointData> = Module(
persistence = persistence,
prefix = "third_party_authorization_",
serializer = Certificate::serialize,
deserializer = Certificate::deserialize
)

internal val thirdPartyIdentityCertificate: Module<Certificate> = Module(
persistence = persistence,
prefix = "third_party_identity_",
serializer = Certificate::serialize,
deserializer = Certificate::deserialize
prefix = "private_third_party_",
serializer = PrivateThirdPartyEndpointData::serialize,
deserializer = PrivateThirdPartyEndpointData::deserialize
)

internal open class Module<T>(
Expand Down
Loading