Enhancement: GeneralName support#353
Conversation
eb899c0 to
fc73548
Compare
ad53e4f to
04b54be
Compare
JesusMcCloud
left a comment
There was a problem hiding this comment.
Even though these are "just" the data classes, they do contain logic that check if an how constraints are fulfilled. These need comprehensive tests. I'm sure there stuff out there and you can probably integrate some from your large cert-validation PR into here
...pensable/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/generalNames/X500Name.kt
Show resolved
Hide resolved
...able/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/RelativeDistinguishedName.kt
Outdated
Show resolved
Hide resolved
...spensable/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/generalNames/DNSName.kt
Show resolved
Hide resolved
...spensable/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/generalNames/DNSName.kt
Outdated
Show resolved
Hide resolved
...able/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/generalNames/EDIPartyName.kt
Outdated
Show resolved
Hide resolved
...ble/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/generalNames/IPAddressName.kt
Outdated
Show resolved
Hide resolved
...ble/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/generalNames/IPAddressName.kt
Outdated
Show resolved
Hide resolved
...ble/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/generalNames/IPAddressName.kt
Outdated
Show resolved
Hide resolved
...spensable/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/generalNames/UriName.kt
Outdated
Show resolved
Hide resolved
...sable/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/generalNames/GeneralName.kt
Show resolved
Hide resolved
JesusMcCloud
left a comment
There was a problem hiding this comment.
the validation logic need further offline discussion.
| return@decodeRethrowing when (oid) { | ||
| CommonName.OID -> str.fold(onSuccess = { CommonName(it) }, onFailure = { CommonName(asn1String) }) | ||
| Country.OID -> str.fold(onSuccess = { Country(it) }, onFailure = { Country(asn1String) }) | ||
| EmailAddress.OID -> str.fold(onSuccess = { EmailAddress(it) }, onFailure = { EmailAddress(asn1String) }) |
There was a problem hiding this comment.
don't all of these enforce validation, since their default constructors are called?
There was a problem hiding this comment.
You're right, fixed this legacy code in bd53929
...able/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/RelativeDistinguishedName.kt
Outdated
Show resolved
Hide resolved
...spensable/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/generalNames/DNSName.kt
Outdated
Show resolved
Hide resolved
...sable/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/generalNames/GeneralName.kt
Outdated
Show resolved
Hide resolved
...spensable/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/generalNames/DNSName.kt
Outdated
Show resolved
Hide resolved
...ble/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/generalNames/IPAddressName.kt
Outdated
Show resolved
Hide resolved
...ble/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/generalNames/IPAddressName.kt
Outdated
Show resolved
Hide resolved
...ensable/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/generalNames/OtherName.kt
Outdated
Show resolved
Hide resolved
...spensable/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/generalNames/UriName.kt
Outdated
Show resolved
Hide resolved
...e/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/generalNames/X400AddressName.kt
Outdated
Show resolved
Hide resolved
82b093c to
09eecc5
Compare
d676787 to
b96e512
Compare
...able/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/RelativeDistinguishedName.kt
Outdated
Show resolved
Hide resolved
| private fun splitFirstUnescaped(input: String, delimiter: Char): List<String> { | ||
| val sb = StringBuilder() | ||
| var escaped = false | ||
| for ((i, c) in input.withIndex()) { | ||
| when { | ||
| escaped -> { | ||
| sb.append('\\').append(c) // preserve the escape | ||
| escaped = false | ||
| } | ||
| c == '\\' -> escaped = true | ||
| c == delimiter -> return listOf(sb.toString(), input.substring(i + 1)) | ||
| else -> sb.append(c) | ||
| } | ||
| } | ||
| return listOf(sb.toString()) | ||
| } |
There was a problem hiding this comment.
Can't we rely on some pre-existing functionality for that? I know serialization has it (think: escaping/unescaping string is virtually any test-based format) but I would expect this to be buried somewhere inside kotlin's stdlib, or any of the dependencies we already use here. When in doublt use Android studio, as it gives you free Tokens for Gemini-powered AI-assistance
There was a problem hiding this comment.
I did refactor the code to use regex, but still didn't find something pre-existing. It is now much cleaner, but not sure if it's satisfactory yet. ae61ba7
There was a problem hiding this comment.
| private fun splitRespectingEscapeAndQuotes(input: String, delimiter: Char): List<String> { | ||
| val parts = mutableListOf<String>() | ||
| val sb = StringBuilder() | ||
| var escaped = false | ||
| var inQuotes = false | ||
|
|
||
| input.forEach { c -> | ||
| when { | ||
| escaped -> { | ||
| sb.append('\\').append(c) // preserve escape | ||
| escaped = false | ||
| } | ||
| c == '\\' -> escaped = true | ||
| c == '"' -> { | ||
| sb.append(c) | ||
| inQuotes = !inQuotes | ||
| } | ||
| c == delimiter && !inQuotes -> { | ||
| parts.add(sb.toString()) | ||
| sb.clear() | ||
| } | ||
| else -> sb.append(c) | ||
| } | ||
| } | ||
|
|
||
| parts.add(sb.toString().trim()) | ||
| return parts | ||
| } | ||
|
|
...able/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/RelativeDistinguishedName.kt
Outdated
Show resolved
Hide resolved
...able/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/generalNames/EDIPartyName.kt
Outdated
Show resolved
Hide resolved
...sable/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/generalNames/GeneralName.kt
Outdated
Show resolved
Hide resolved
b96e512 to
ae61ba7
Compare
JesusMcCloud
left a comment
There was a problem hiding this comment.
I really think i caught the last loose ends in this cycle.
...able/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/RelativeDistinguishedName.kt
Outdated
Show resolved
Hide resolved
...able/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/RelativeDistinguishedName.kt
Outdated
Show resolved
Hide resolved
...able/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/RelativeDistinguishedName.kt
Outdated
Show resolved
Hide resolved
| import at.asitplus.test.FreeSpec | ||
| import io.kotest.matchers.shouldBe | ||
|
|
||
| class GeneralNamesConstrainsTest : FreeSpec ({ |
There was a problem hiding this comment.
Can we test all those against JCA / BouncyCastle in addition to your tests?
There was a problem hiding this comment.
Tests are based on the BouncyCastle tests
There was a problem hiding this comment.
then please add a comment to the source of the test
| import at.asitplus.test.FreeSpec | ||
| import io.kotest.matchers.shouldBe | ||
|
|
||
| class X500NameParsingTest : FreeSpec ({ |
There was a problem hiding this comment.
can we also test those against bouncy castle / JCA?
There was a problem hiding this comment.
Tests are based on the BouncyCastle tests
There was a problem hiding this comment.
same, please link to the original BC tests in a comment
...able/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/RelativeDistinguishedName.kt
Outdated
Show resolved
Hide resolved
...able/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/RelativeDistinguishedName.kt
Outdated
Show resolved
Hide resolved
...able/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/RelativeDistinguishedName.kt
Outdated
Show resolved
Hide resolved
...able/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/RelativeDistinguishedName.kt
Outdated
Show resolved
Hide resolved
...able/src/commonMain/kotlin/at/asitplus/signum/indispensable/pki/generalNames/EDIPartyName.kt
Show resolved
Hide resolved
JesusMcCloud
left a comment
There was a problem hiding this comment.
nitpicks and one open point for an offline elaboration
| data class RelativeDistinguishedName(val attrsAndValues: List<AttributeTypeAndValue>) : Asn1Encodable<Asn1Set> { | ||
| class RelativeDistinguishedName private constructor( | ||
| val attrsAndValues: List<AttributeTypeAndValue>, | ||
| performValidation: Boolean = false, |
There was a problem hiding this comment.
I'd omit the default value, to prevent even the possibility of accidentally calling the wrong c'tor
| constructor(str: Asn1String) : this(Asn1Primitive(str.tag, str.value.encodeToByteArray())) { | ||
| if (isValid == false) throw Asn1Exception("Invalid Organization!") | ||
| } |
There was a problem hiding this comment.
seeing this pattern everywhere: can't we pull that up as a protected c'tor in the base class?
| private fun splitFirstUnescaped(input: String, delimiter: Char): List<String> { | ||
| val sb = StringBuilder() | ||
| var escaped = false | ||
| for ((i, c) in input.withIndex()) { | ||
| when { | ||
| escaped -> { | ||
| sb.append('\\').append(c) // preserve the escape | ||
| escaped = false | ||
| } | ||
| c == '\\' -> escaped = true | ||
| c == delimiter -> return listOf(sb.toString(), input.substring(i + 1)) | ||
| else -> sb.append(c) | ||
| } | ||
| } | ||
| return listOf(sb.toString()) | ||
| } |
There was a problem hiding this comment.
| import at.asitplus.test.FreeSpec | ||
| import io.kotest.matchers.shouldBe | ||
|
|
||
| class GeneralNamesConstrainsTest : FreeSpec ({ |
There was a problem hiding this comment.
then please add a comment to the source of the test
| import at.asitplus.test.FreeSpec | ||
| import io.kotest.matchers.shouldBe | ||
|
|
||
| class X500NameParsingTest : FreeSpec ({ |
There was a problem hiding this comment.
same, please link to the original BC tests in a comment
3dcddf0 to
82e036e
Compare
…ssuer # Conflicts: # supreme/src/commonTest/kotlin/at/asitplus/signum/supreme/sign/EphemeralSignerCommonTests.kt
# Conflicts: # CHANGELOG.md # Conflicts: # CHANGELOG.md # Conflicts: # CHANGELOG.md
…e, minor fixes in parsing from string logic
…validation is not implemented
…idation for generalNames without one
…f attrTypeAndValues
…ing(), add tests for parsing functions
a3c4079 to
7db7e92
Compare
* Refactor AlternativeNames to use GeneralName * add X500Name and refactor X509Cert to use this class as subject and issuer --------- Co-authored-by: Bernd Prünster <bernd.pruenster@a-sit.at>
AlternativeNamesfor SAN/IAN extractionGeneralNameand subclasses