Skip to content

Commit

Permalink
Added --verbose, upgraded 3rd party
Browse files Browse the repository at this point in the history
-v now is for --verbose and not anymore for --version.  --verbose right now
only shows longer descriptions for extended key usages
  • Loading branch information
nkiesel committed Dec 9, 2023
1 parent ff9b903 commit 53b75f2
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 34 deletions.
18 changes: 8 additions & 10 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,26 @@ plugins {
}

group = "nkiesel.org"
version = "2.3.1"
version = "2.4.0"

repositories {
mavenCentral()
}

dependencies {
implementation("com.github.ajalt.clikt:clikt:4.2.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
implementation("org.http4k:http4k-core:5.8.4.0")
implementation("org.http4k:http4k-client-okhttp:5.8.4.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2")
implementation("org.http4k:http4k-core:5.10.5.0")
implementation("org.http4k:http4k-client-okhttp:5.10.5.0")
implementation("com.github.ajalt.mordant:mordant:2.1.0")

testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.0")
testImplementation("io.kotest:kotest-assertions-core:5.7.2")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.1")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.1")
testImplementation("io.kotest:kotest-assertions-core:5.8.0")
}

kotlin {
compilerOptions {
jvmTarget = JvmTarget.JVM_17
}
jvmToolchain(17)
}

application {
Expand Down
77 changes: 53 additions & 24 deletions src/main/kotlin/CertificateHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ import com.github.ajalt.mordant.rendering.TextColors.*
import com.github.ajalt.mordant.terminal.Terminal
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import kotlinx.serialization.json.*
import org.http4k.client.OkHttp
import org.http4k.client.PreCannedOkHttpClients
import org.http4k.core.Method
Expand Down Expand Up @@ -65,25 +62,48 @@ enum class OutputFormat {
SUMMARY, TEXT, PEM, BASE64, CONFIG
}

private val keyUsages = arrayOf(
"Digital signature",
"Non-repudiation",
"Key encipherment",
"Data encipherment",
"Key agreement",
"Certificate signing",
"CRL signing",
"Encipher only",
"Decipher only",
// https://www.rfc-editor.org/rfc/rfc5280.html#section-4.2.1.3
private val keyUsages = mapOf(
0 to "Digital signature",
1 to "content commitment",
2 to "Key encipherment",
3 to "Data encipherment",
4 to "Key agreement",
5 to "Certificate signing",
6 to "CRL signing",
7 to "Encipher only",
8 to "Decipher only",
)

private class EKP(val name: String, val description: String) {
fun toString(verbose: Boolean) = if (verbose) "$name: $description" else name
}

// https://www.rfc-editor.org/rfc/rfc5280.html#section-4.2.1.12
// name and description from https://oid-rep.orange-labs.fr/get/1.3.6.1.5.5.7.3 and https://www.rfc-editor.org/errata/eid5802
private val extendedKeyUsages = mapOf(
"1.3.6.1.5.5.7.3.1" to "Server authentication",
"1.3.6.1.5.5.7.3.2" to "Client authentication",
"1.3.6.1.5.5.7.3.3" to "Code signing",
"1.3.6.1.5.5.7.3.4" to "Email",
"1.3.6.1.5.5.7.3.8" to "Timestamping",
"1.3.6.1.5.5.7.3.9[a]" to "OCSP Signing",
"1.3.6.1.5.5.7.3.1" to EKP("serverAuth", "Transport Layer Security (TLS) server authentication"),
"1.3.6.1.5.5.7.3.2" to EKP("clientAuth", "Transport Layer Security (TLS) client authentication"),
"1.3.6.1.5.5.7.3.3" to EKP("codeSigning", "Signing of downloadable executable code"),
"1.3.6.1.5.5.7.3.4" to EKP("emailProtection", "E-mail protection"),
"1.3.6.1.5.5.7.3.5" to EKP("ipsecEndSystem", "Internet Protocol SECurity (IPSEC) end system certificate"),
"1.3.6.1.5.5.7.3.6" to EKP("ipsecTunnel", "Internet Protocol SECurity (IPSEC) tunnel certificate"),
"1.3.6.1.5.5.7.3.7" to EKP("ipsecUser", "Internet Protocol SECurity (IPSEC) user certificate"),
"1.3.6.1.5.5.7.3.8" to EKP("timeStamping", "Binding the hash of an object to a time"),
"1.3.6.1.5.5.7.3.9" to EKP("OCSPSigning", "Signing Online Certificate Status Protocol (OCSP) responses"),
"1.3.6.1.5.5.7.3.21" to EKP("secureShellClient", "Key can be used for a Secure Shell client"),
"1.3.6.1.5.5.7.3.22" to EKP("secureShellServer", "Key can be used for a Secure Shell server"),
"1.3.6.1.5.5.7.3.33" to EKP("rpcTLSClient", "id-kp-rpcTLSClient"),
"1.3.6.1.5.5.7.3.34" to EKP("rpcTLSServer", "id-kp-rpcTLSServer"),
"1.3.6.1.5.5.7.3.36" to EKP("documentSigning", "Extended key purpose for document signing in certificates"),
"1.3.6.1.5.5.7.3.37" to EKP("jwt", "id-kp-jwt"),
"1.3.6.1.5.5.7.3.38" to EKP("httpContentEncrypt", "id-kp-httpContentEncrypt"),
"1.3.6.1.5.5.7.3.39" to EKP("oauthAccessTokenSigning", "id-kp-oauthAccessTokenSigning"),
// https://access.redhat.com/documentation/en-us/red_hat_certificate_system/9/html/administration_guide/standard_x.509_v3_certificate_extensions#Discussion-PKIX_Extended_Key_Usage_Extension_Uses
"1.3.6.1.4.1.311.10.3.1" to EKP("CTLSigning", "Certificate trust list signing"),
"1.3.6.1.4.1.311.10.3.3" to EKP("SGC", "Microsoft Server Gated Crypto (SGC)"),
"1.3.6.1.4.1.311.10.3.4" to EKP("EFS", "Microsoft Encrypted File System"),
"2.16.840.1.113730.4.1" to EKP("export-approved", "Netscape Server Gated Crypto (SGC)"),
)

typealias X509List = List<X509Certificate>
Expand Down Expand Up @@ -112,7 +132,7 @@ class CertificateHelper : CliktCommand(
completionOption()
versionOption(
javaClass.getResourceAsStream("version")?.bufferedReader()?.use { it.readLine() } ?: "development",
names = setOf("-v", "--version")
names = setOf("--version")
)
}

Expand Down Expand Up @@ -140,6 +160,7 @@ class CertificateHelper : CliktCommand(
private val timeout by option(help = "Server connection timeout; 0s for no timeout")
.convert { Duration.parse(it) }.default(5.seconds)
private val rootCAs by option("--rootCAs", help = "list root CAs, filter with optional regex").optionalValue(".*")
private val verbose by option("-v", "--verbose", help = "more verbose output").flag()

private val content = StringWriter()
private val writer = PrintWriter(content)
Expand Down Expand Up @@ -335,8 +356,15 @@ class CertificateHelper : CliktCommand(
}

var json: JsonElement? = parser.parseToJsonElement(config)
val arrayRegex = Regex("""(.+)\[(\d+)]""")
for (comp in configKey.split(".")) {
json = json?.jsonObject?.get(comp)
val array = arrayRegex.matchEntire(comp)
json = if (array !== null) {
val (name, index) = array.destructured
json?.jsonObject?.get(name)?.jsonArray?.get(index.toInt())
} else {
json?.jsonObject?.get(comp)
}
}
if (json == null) {
error(input, "Cannot extract $configKey")
Expand Down Expand Up @@ -527,10 +555,11 @@ class CertificateHelper : CliktCommand(
}

fun keyUsage(data: BooleanArray) =
data.mapIndexed { idx, b -> if (b && idx in keyUsages.indices) keyUsages[idx] else null }
data.mapIndexed { idx, b -> if (b) keyUsages[idx] ?: "bit $idx set to true" else null }
.filterNotNull().joinToString()

fun extKeyUsage(data: List<String>) = data.joinToString { extendedKeyUsages[it] ?: "???" }
fun extKeyUsage(data: List<String>) =
data.joinToString { extendedKeyUsages[it]?.toString(verbose) ?: it }

with(writer) {
with(cert) {
Expand Down

0 comments on commit 53b75f2

Please sign in to comment.