Skip to content

Commit

Permalink
fix(CertificateRotation): Encode chain with explicit tagging (#222)
Browse files Browse the repository at this point in the history
Per the spec. Found bug whilst testing compatibility with JS implementation.
  • Loading branch information
gnarea authored Feb 22, 2022
1 parent d434aae commit c9bf51a
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package tech.relaycorp.relaynet.messages

import org.bouncycastle.asn1.ASN1TaggedObject
import org.bouncycastle.asn1.DEROctetString
import org.bouncycastle.asn1.DERSequence
import tech.relaycorp.relaynet.wrappers.asn1.ASN1Exception
Expand All @@ -11,8 +10,7 @@ import tech.relaycorp.relaynet.wrappers.x509.CertificateException
class CertificateRotation(val subjectCertificate: Certificate, val chain: List<Certificate>) {
fun serialize(): ByteArray {
val chainSequence = ASN1Utils.makeSequence(
chain.map { DEROctetString(it.serialize()) },
false
chain.map { DEROctetString(it.serialize()) }
)
val sequence = ASN1Utils.serializeSequence(
listOf(
Expand Down Expand Up @@ -72,10 +70,12 @@ class CertificateRotation(val subjectCertificate: Certificate, val chain: List<C
throw InvalidMessageException("Chain is malformed", exc)
}
val chain = try {
chainSequence.map { ASN1Utils.getOctetString(it as ASN1TaggedObject) }
chainSequence.map { DEROctetString.getInstance(it) }
.map { Certificate.deserialize(it.octets) }
} catch (exc: CertificateException) {
throw InvalidMessageException("Chain contains malformed certificate", exc)
} catch (exc: IllegalArgumentException) {
throw InvalidMessageException("Chain contains malformed certificate", exc)
}

return CertificateRotation(subjectCertificate, chain)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package tech.relaycorp.relaynet.messages
import kotlin.test.assertEquals
import kotlin.test.assertTrue
import org.bouncycastle.asn1.ASN1Sequence
import org.bouncycastle.asn1.ASN1TaggedObject
import org.bouncycastle.asn1.DEROctetString
import org.bouncycastle.asn1.DERVisibleString
import org.junit.jupiter.api.Nested
Expand Down Expand Up @@ -71,7 +70,7 @@ class CertificateRotationTest {
val chainSequence = ASN1Sequence.getInstance(sequenceItems[1], false)
assertEquals(1, chainSequence.size())
val issuerSerialized =
ASN1Utils.getOctetString(chainSequence.first() as ASN1TaggedObject).octets
DEROctetString.getInstance(chainSequence.first()).octets
assertEquals(issuerCertificate, Certificate.deserialize(issuerSerialized))
}
}
Expand Down Expand Up @@ -161,7 +160,7 @@ class CertificateRotationTest {
listOf(
DEROctetString(subjectCertificate.serialize()),
ASN1Utils.makeSequence(
listOf(DERVisibleString("malformed")), false
listOf(DEROctetString("malformed".toByteArray()))
)
),
false
Expand All @@ -175,6 +174,26 @@ class CertificateRotationTest {
assertTrue(exception.cause is CertificateException)
}

@Test
fun `Chain certificates should be OCTET STRINGs`() {
val serialization = CertificateRotation.FORMAT_SIGNATURE + ASN1Utils.serializeSequence(
listOf(
DEROctetString(subjectCertificate.serialize()),
ASN1Utils.makeSequence(
listOf(DERVisibleString("malformed"))
)
),
false
)

val exception = assertThrows<InvalidMessageException> {
CertificateRotation.deserialize(serialization)
}

assertEquals("Chain contains malformed certificate", exception.message)
assertTrue(exception.cause is IllegalArgumentException)
}

@Test
fun `A new instance should be returned if serialization is valid`() {
val rotation = CertificateRotation(subjectCertificate, listOf(issuerCertificate))
Expand Down

0 comments on commit c9bf51a

Please sign in to comment.