From 9dfbc9391fe27fc631bdf61e3e51dd3a124a4c60 Mon Sep 17 00:00:00 2001 From: Antoine A <> Date: Wed, 27 Mar 2024 00:11:10 +0100 Subject: Improve self-signed certificate --- common/src/main/kotlin/crypto/utils.kt | 80 +++++++++------------- common/src/test/kotlin/CryptoUtilTest.kt | 6 +- .../main/kotlin/tech/libeufin/nexus/KeyFiles.kt | 4 +- nexus/src/main/kotlin/tech/libeufin/nexus/PDF.kt | 2 +- .../tech/libeufin/nexus/ebics/EbicsConstants.kt | 9 ++- .../tech/libeufin/nexus/ebics/EbicsKeyMng.kt | 6 +- nexus/src/test/kotlin/XmlUtilTest.kt | 2 +- 7 files changed, 49 insertions(+), 60 deletions(-) diff --git a/common/src/main/kotlin/crypto/utils.kt b/common/src/main/kotlin/crypto/utils.kt index 1228eb91..10fa195e 100644 --- a/common/src/main/kotlin/crypto/utils.kt +++ b/common/src/main/kotlin/crypto/utils.kt @@ -43,12 +43,8 @@ import javax.crypto.spec.PBEParameterSpec import javax.crypto.spec.SecretKeySpec import tech.libeufin.common.* -/** - * Helpers for dealing with cryptographic operations in EBICS / LibEuFin. - */ +/** Helpers for dealing with cryptographic operations in EBICS / LibEuFin */ object CryptoUtil { - // TODO split common and ebics crypto - /** * RSA key pair. */ @@ -64,10 +60,8 @@ object CryptoUtil { private val provider = BouncyCastleProvider() - /** - * Load an RSA private key from its binary PKCS#8 encoding. - */ - fun loadRsaPrivateKey(encodedPrivateKey: ByteArray): RSAPrivateCrtKey { + /** Load an RSA private key from its binary PKCS#8 encoding */ + fun loadRSAPrivate(encodedPrivateKey: ByteArray): RSAPrivateCrtKey { val spec = PKCS8EncodedKeySpec(encodedPrivateKey) val priv = KeyFactory.getInstance("RSA").generatePrivate(spec) if (priv !is RSAPrivateCrtKey) @@ -75,10 +69,8 @@ object CryptoUtil { return priv } - /** - * Load an RSA public key from its binary X509 encoding. - */ - fun loadRsaPublicKey(encodedPublicKey: ByteArray): RSAPublicKey { + /** Load an RSA public key from its binary X509 encoding */ + fun loadRSAPublic(encodedPublicKey: ByteArray): RSAPublicKey { val spec = X509EncodedKeySpec(encodedPublicKey) val pub = KeyFactory.getInstance("RSA").generatePublic(spec) if (pub !is RSAPublicKey) @@ -86,52 +78,42 @@ object CryptoUtil { return pub } - /** - * Load an RSA public key from its components. - * - * @param exponent - * @param modulus - * @return key - */ - fun loadRsaPublicKeyFromComponents(modulus: ByteArray, exponent: ByteArray): RSAPublicKey { + /** Create an RSA public key from its components: [modulus] and [exponent] */ + fun RSAPublicFromComponents(modulus: ByteArray, exponent: ByteArray): RSAPublicKey { val modulusBigInt = BigInteger(1, modulus) val exponentBigInt = BigInteger(1, exponent) - - val keyFactory = KeyFactory.getInstance("RSA") - val tmp = RSAPublicKeySpec(modulusBigInt, exponentBigInt) - return keyFactory.generatePublic(tmp) as RSAPublicKey + val spec = RSAPublicKeySpec(modulusBigInt, exponentBigInt) + return KeyFactory.getInstance("RSA").generatePublic(spec) as RSAPublicKey } - fun loadRsaPublicKeyFromCertificate(certificate: ByteArray): RSAPublicKey { - val cf = CertificateFactory.getInstance("X.509"); - val c = cf.generateCertificate(certificate.inputStream()); - return c.getPublicKey() as RSAPublicKey + /** Extract an RSA public key from a [raw] X.509 certificate */ + fun RSAPublicFromCertificate(raw: ByteArray): RSAPublicKey { + val certificate = CertificateFactory.getInstance("X.509").generateCertificate(raw.inputStream()); + return certificate.getPublicKey() as RSAPublicKey } - /** - * Load an RSA public key from its binary X509 encoding. - */ - fun getRsaPublicFromPrivate(rsaPrivateCrtKey: RSAPrivateCrtKey): RSAPublicKey { - val spec = RSAPublicKeySpec(rsaPrivateCrtKey.modulus, rsaPrivateCrtKey.publicExponent) - val pub = KeyFactory.getInstance("RSA").generatePublic(spec) - if (pub !is RSAPublicKey) - throw Exception("wrong encoding") - return pub + /** Generate an RSA public key from a [private] one */ + fun RSAPublicFromPrivate(private: RSAPrivateCrtKey): RSAPublicKey { + val spec = RSAPublicKeySpec(private.modulus, private.publicExponent) + return KeyFactory.getInstance("RSA").generatePublic(spec) as RSAPublicKey } - fun certificateFromPrivate(rsaPrivateCrtKey: RSAPrivateCrtKey): X509Certificate { - val now = System.currentTimeMillis() + /** Generate a self-signed X.509 certificate from an RSA [private] key */ + fun X509CertificateFromRSAPrivate(private: RSAPrivateCrtKey, name: String): X509Certificate { + val start = Date() val calendar = Calendar.getInstance() - calendar.time = Date(now) - calendar.add(Calendar.YEAR, 1) // TODO certificate validity + calendar.time = start + calendar.add(Calendar.YEAR, 1_000) + val end = calendar.time + val name = X500Name("CN=$name") val builder = JcaX509v3CertificateBuilder( - X500Name("CN=test"), // TODO certificate CN - BigInteger(now.toString()), // TODO certificate serial number - Date(now), - calendar.time, - X500Name("CN=test"), - getRsaPublicFromPrivate(rsaPrivateCrtKey) + name, + BigInteger(20, Random()), + start, + end, + name, + RSAPublicFromPrivate(private) ) @@ -148,7 +130,7 @@ object CryptoUtil { )) builder.addExtension(Extension.basicConstraints, true, BasicConstraints(true)) - val certificate = JcaContentSignerBuilder("SHA256WithRSA").build(rsaPrivateCrtKey) + val certificate = JcaContentSignerBuilder("SHA256WithRSA").build(private) return JcaX509CertificateConverter() .setProvider(provider) .getCertificate(builder.build(certificate)) diff --git a/common/src/test/kotlin/CryptoUtilTest.kt b/common/src/test/kotlin/CryptoUtilTest.kt index 82f18ab9..f76701ad 100644 --- a/common/src/test/kotlin/CryptoUtilTest.kt +++ b/common/src/test/kotlin/CryptoUtilTest.kt @@ -35,7 +35,7 @@ class CryptoUtilTest { @Test fun loadFromModulusAndExponent() { val keyPair = CryptoUtil.generateRsaKeyPair(1024) - val pub2 = CryptoUtil.loadRsaPublicKeyFromComponents( + val pub2 = CryptoUtil.RSAPublicFromComponents( keyPair.public.modulus.toByteArray(), keyPair.public.publicExponent.toByteArray() ) @@ -57,7 +57,7 @@ class CryptoUtilTest { val encodedPriv = keyPair.private.encoded val encodedPub = keyPair.public.encoded val otherKeyPair = - CryptoUtil.RsaCrtKeyPair(CryptoUtil.loadRsaPrivateKey(encodedPriv), CryptoUtil.loadRsaPublicKey(encodedPub)) + CryptoUtil.RsaCrtKeyPair(CryptoUtil.loadRSAPrivate(encodedPriv), CryptoUtil.loadRSAPublic(encodedPub)) assertEquals(keyPair.private, otherKeyPair.private) assertEquals(keyPair.public, otherKeyPair.public) } @@ -129,7 +129,7 @@ class CryptoUtilTest { val expectedHash = expectedHashStr.replace(" ", "").replace("\n", "").toByteArray(Charsets.UTF_8) - val pub = CryptoUtil.loadRsaPublicKeyFromComponents(moduloStr.decodeUpHex(), exponentStr.decodeUpHex()) + val pub = CryptoUtil.RSAPublicFromComponents(moduloStr.decodeUpHex(), exponentStr.decodeUpHex()) println("echoed pub exp: ${pub.publicExponent.encodeHex()}") println("echoed pub mod: ${pub.modulus.encodeHex()}") diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/KeyFiles.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/KeyFiles.kt index fd91cfd4..b4acbb75 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/KeyFiles.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/KeyFiles.kt @@ -58,7 +58,7 @@ object RSAPublicKeySerializer : KSerializer { override fun deserialize(decoder: Decoder): RSAPublicKey { val fieldValue = decoder.decodeString() val bytes = Base32Crockford.decode(fieldValue) - return CryptoUtil.loadRsaPublicKey(bytes) + return CryptoUtil.loadRSAPublic(bytes) } } @@ -76,7 +76,7 @@ object RSAPrivateCrtKeySerializer : KSerializer { override fun deserialize(decoder: Decoder): RSAPrivateCrtKey { val fieldValue = decoder.decodeString() val bytes = Base32Crockford.decode(fieldValue) - return CryptoUtil.loadRsaPrivateKey(bytes) + return CryptoUtil.loadRSAPrivate(bytes) } } diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/PDF.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/PDF.kt index a485477c..dd595d31 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/PDF.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/PDF.kt @@ -73,7 +73,7 @@ fun generateKeysPdf( } fun writeKey(doc: Document, priv: RSAPrivateCrtKey) { - val pub = CryptoUtil.getRsaPublicFromPrivate(priv) + val pub = CryptoUtil.RSAPublicFromPrivate(priv) val hash = CryptoUtil.getEbicsPublicKeyHash(pub) doc.add(Paragraph("Exponent:\n${formatHex(pub.publicExponent.toByteArray())}")) doc.add(Paragraph("Modulus:\n${formatHex(pub.modulus.toByteArray())}")) diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsConstants.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsConstants.kt index fc217c2a..8841866f 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsConstants.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsConstants.kt @@ -46,9 +46,16 @@ enum class EbicsReturnCode(val code: String) { EBICS_TX_SEGMENT_NUMBER_EXCEEDED("091104"), EBICS_INVALID_REQUEST_CONTENT("091113"), EBICS_PROCESSING_ERROR("091116"), - // Key-Management errors + EBICS_KEYMGMT_UNSUPPORTED_VERSION_SIGNATURE("091201"), + EBICS_KEYMGMT_UNSUPPORTED_VERSION_AUTHENTICATION("091202"), + EBICS_KEYMGMT_UNSUPPORTED_VERSION_ENCRYPTION("091203"), + EBICS_KEYMGMT_KEYLENGTH_ERROR_SIGNATURE("091204"), + EBICS_KEYMGMT_KEYLENGTH_ERROR_AUTHENTICATION("091205"), + EBICS_KEYMGMT_KEYLENGTH_ERROR_ENCRYPTION("091206"), + EBICS_X509_CERTIFICATE_EXPIRED("091208"), + EBICS_X509_CERTIFICATE_NOT_VALID_YET("091209"), EBICS_X509_WRONG_KEY_USAGE("091210"), EBICS_X509_WRONG_ALGORITHM("091211"), EBICS_X509_INVALID_THUMBPRINT("091212"), diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsKeyMng.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsKeyMng.kt index 02db79a0..9141430a 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsKeyMng.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsKeyMng.kt @@ -111,7 +111,7 @@ class EbicsKeyMng( private fun XmlBuilder.RSAKeyXml(key: RSAPrivateCrtKey) { if (ebics3) { - val cert = CryptoUtil.certificateFromPrivate(key) + val cert = CryptoUtil.X509CertificateFromRSAPrivate(key, cfg.myIbanAccount.name) el("ds:X509Data") { el("ds:X509Certificate", cert.encoded.encodeBase64()) } @@ -175,10 +175,10 @@ class EbicsKeyMng( fun XmlDestructor.rsaPubKey(): RSAPublicKey { val cert = opt("X509Data")?.one("X509Certificate")?.text()?.decodeBase64() return if (cert != null) { - CryptoUtil.loadRsaPublicKeyFromCertificate(cert) + CryptoUtil.RSAPublicFromCertificate(cert) } else { one("PubKeyValue").one("RSAKeyValue") { - CryptoUtil.loadRsaPublicKeyFromComponents( + CryptoUtil.RSAPublicFromComponents( one("Modulus").text().decodeBase64(), one("Exponent").text().decodeBase64(), ) diff --git a/nexus/src/test/kotlin/XmlUtilTest.kt b/nexus/src/test/kotlin/XmlUtilTest.kt index 03941f3f..a60e0904 100644 --- a/nexus/src/test/kotlin/XmlUtilTest.kt +++ b/nexus/src/test/kotlin/XmlUtilTest.kt @@ -67,7 +67,7 @@ class XmlUtilTest { val doc = XMLUtil.parseIntoDom(docText) val keyStream = classLoader.getResourceAsStream("signature1/public_key.txt") val keyBytes = keyStream.decodeBase64().readAllBytes() - val key = CryptoUtil.loadRsaPublicKey(keyBytes) + val key = CryptoUtil.loadRSAPublic(keyBytes) assertTrue(XMLUtil.verifyEbicsDocument(doc, key, "H004")) } } \ No newline at end of file -- cgit v1.2.3