Lightweight X.509 certificate toolkit for Kotlin/JVM. Build self-signed certs, CSRs, CRLs, and work with PEM/DER encoding, all using JDK standard libraries. No BouncyCastle, no Guava.
- Self-signed certificates β X.509v3 with SAN, Basic Constraints, key identifiers (EC keys)
- CSR creation β PKCS#10 Certificate Signing Requests with SAN support
- CRL support β parse, build, and check certificate revocation lists
- PEM read/write β load and encode certificates, private keys, public keys
- DER DSL β type-safe Kotlin DSL for building ASN.1 DER structures
- Private key formats β PKCS#8, PKCS#8 encrypted, PKCS#1 (RSA, DSA, EC)
- TLS scanning β connect to any host and capture the certificate chain
Requires JDK 21+
dependencies {
implementation("dev.suresh.certkit:certkit:1.0.0-SNAPSHOT")
}val keyPair = newEcKeyPair()
val today = Clock.System.todayIn(TimeZone.UTC)
val cert = Cert.buildSelfSigned(
keyPair = keyPair,
serialNumber = 1,
issuer = X500Principal("CN=My CA,O=TestOrg"),
subject = X500Principal("CN=My CA,O=TestOrg"),
notBefore = today,
notAfter = today + DatePeriod(days = 30),
sans = listOf(San.Dns("localhost"), San.Dns("*.local"), San.Ip("127.0.0.1")),
)
println(cert.pem)An Instant overload is also available for precise control over validity times.
cert.commonName // "My CA"
cert.subjectAltNames // ["localhost", "*.local", "127.0.0.1"]
cert.expiryDateUtc // 2026-04-07T23:59:59
cert.isExpired // false
cert.expiresIn // 30d 0h ...
cert.isCA // true
cert.selfSigned // true
cert.signedBy(caCert) // true// Load
val privateKey = Pem.loadPrivateKey(Path("server.key"), keyPassword = "secret")
val publicKey = Pem.loadPublicKey(Path("server.pub"))
val certs = Pem.readCertificateChain(Path("chain.crt"))
val keyStore = Pem.loadKeyStore(Path("server.crt"), Path("server.key"))
val trustStore = Pem.loadTrustStore(Path("ca.crt"))
// Encode β .pem extension on all major types
publicKey.pem // -----BEGIN PUBLIC KEY-----
privateKey.pem // -----BEGIN PRIVATE KEY-----
certificate.pem // -----BEGIN CERTIFICATE-----
csr.pem // -----BEGIN CERTIFICATE REQUEST-----
crl.pem // -----BEGIN X509 CRL-----
// PKCS#8 export (encrypted & unencrypted)
privateKey.toPkcs8Pem() // -----BEGIN PRIVATE KEY-----
privateKey.toPkcs8Pem(password = "secret") // -----BEGIN ENCRYPTED PRIVATE KEY-----
// PKCS#1 export (RSA only)
rsaPrivateKey.toPkcs1Pem() // -----BEGIN RSA PRIVATE KEY-----// Parse a Base64-encoded PKCS#12 keystore into PEM components
val bundle = parseKeyStore(base64Data, storePass = "changeit")
// Export with encrypted PKCS#8 key
val encrypted = parseKeyStore(base64Data, "changeit", format = KeyFormat.Pkcs8(keyPass = "secret"))
// Export with PKCS#1 key (RSA only, no encryption)
val pkcs1 = parseKeyStore(base64Data, "changeit", format = KeyFormat.Pkcs1)
// PemBundle fields
bundle.key // PEM-encoded private key
bundle.cert // PEM-encoded leaf certificate
bundle.certChain // PEM-encoded CA certificate chain
bundle.keyPass // key passwordval csr = Csr.create(
x500Name = "CN=app.example.com,O=Acme",
algorithmName = "SHA256withRSA",
keyPair = keyPair,
sans = listOf(San.Dns("app.example.com"), San.Ip("10.0.0.1")),
)
println(csr.pem)val crl = Crl.build(
keyPair = caKeyPair,
issuer = X500Principal("CN=My CA,O=Acme"),
thisUpdate = Clock.System.now(),
nextUpdate = Clock.System.now() + 30.days,
revokedSerials = listOf(42L, 99L),
)
cert.isRevokedBy(crl) // check revocation
Crl.distributionPoints(cert) // extract CRL URLsType-safe Kotlin DSL for building ASN.1 DER-encoded structures:
val encoded: ByteArray = seq {
integer(1L)
boolean(true)
seq {
oid("2.5.29.14")
octetString(byteArrayOf(0x01, 0x02))
}
utcTime(Clock.System.now())
explicitTag(0) { integer(2L) }
}All standard ASN.1 types are supported: integer, boolean, bitString, octetString, oid,
utcTime, nullValue, tag, implicitTag, explicitTag, seq, and set.
// Scan remote server certificates
val chain = scanCertificates("github.com")
chain.forEach { println("${it.commonName} β expires ${it.expiryDateUtc}") }
| Category | Formats |
|---|---|
| Private keys | PKCS#8, PKCS#8 encrypted, PKCS#1 (RSA, DSA, EC) |
| Public keys | X.509/SPKI, PKCS#1 RSA |
| Certificates | X.509v3 (PEM & DER) |
| CRLs | X.509 CRL (PEM & DER) |
| Key algorithms | RSA, EC (secp256r1, secp384r1, β¦), DSA |
| Cert builder | EC keys (SHA256withECDSA) |
./amper build # Build
./amper test # Test
./amper publish mavenLocal # Publish to local Maven repositoryThanks to the Airlift project. The crypto and DER/PEM logic is adapted from its security module, rewritten as idiomatic Kotlin without the Guava dependency.
Apache 2.0 β see LICENSE for details.
