libeufin

Integration and sandbox testing for FinTech APIs and data formats
Log | Files | Refs | Submodules | README | LICENSE

commit 3c7ff7037a26de936f19754e8427e9d9fb95e6f3
parent 687f0719da1fbbecf7454b66231db02483447fc8
Author: Florian Dold <florian.dold@gmail.com>
Date:   Thu, 30 Jan 2020 14:40:17 +0100

implement public key dumping for nexus ebics subscribers

Diffstat:
Mnexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt | 7+++++++
Mnexus/src/main/kotlin/tech/libeufin/nexus/Main.kt | 26++++++++++++++++++++++++++
Msandbox/src/main/python/libeufin-cli | 21+++++++++++++++++++++
Mutil/src/main/kotlin/CryptoUtil.kt | 2++
4 files changed, 56 insertions(+), 0 deletions(-)

diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt @@ -32,6 +32,13 @@ data class EbicsKeysBackup( val passphrase: String? = null ) + +data class EbicsPubKeyInfo( + val authPub: String, + val encPub: String, + val sigPub: String +) + /** * This object is POSTed by clients _after_ having created * a EBICS subscriber at the sandbox. diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt @@ -38,6 +38,7 @@ import io.ktor.response.respondText import io.ktor.routing.* import io.ktor.server.engine.embeddedServer import io.ktor.server.netty.Netty +import io.ktor.util.encodeBase64 import org.jetbrains.exposed.dao.EntityID import org.jetbrains.exposed.exceptions.ExposedSQLException import org.jetbrains.exposed.sql.StdOutSqlLogger @@ -584,6 +585,31 @@ fun main() { ) return@post } + + get("/ebics/subscribers/{id}/pubkeys") { + val id = expectId(call.parameters["id"]) + val response = transaction { + val subscriber = EbicsSubscriberEntity.findById(id) ?: throw SubscriberNotFoundError( + HttpStatusCode.NotFound + ) + val authPriv = CryptoUtil.loadRsaPrivateKey(subscriber.authenticationPrivateKey.toByteArray()) + val authPub = CryptoUtil.getRsaPublicFromPrivate(authPriv) + val encPriv = CryptoUtil.loadRsaPrivateKey(subscriber.encryptionPrivateKey.toByteArray()) + val encPub = CryptoUtil.getRsaPublicFromPrivate(encPriv) + val sigPriv = CryptoUtil.loadRsaPrivateKey(subscriber.signaturePrivateKey.toByteArray()) + val sigPub = CryptoUtil.getRsaPublicFromPrivate(sigPriv) + EbicsPubKeyInfo( + bytesToBase64(authPub.encoded), + bytesToBase64(encPub.encoded), + bytesToBase64(sigPub.encoded) + ) + } + call.respond( + HttpStatusCode.OK, + response + ) + } + /* performs a keys backup */ post("/ebics/subscribers/{id}/backup") { val id = expectId(call.parameters["id"]) diff --git a/sandbox/src/main/python/libeufin-cli b/sandbox/src/main/python/libeufin-cli @@ -157,6 +157,27 @@ def restore(obj, account_id, backup_file, nexus_base_url): print("Status code: {}".format(response.status_code)) print("Nexus says: {}".format(response.content.decode("utf-8"))) +@ebics.command(help="Obtain public keys of a nexus ebics account") +@click.pass_obj +@click.option( + "--account-id", + help="Numerical ID of the customer at the Nexus", + required=True +) +@click.argument( + "nexus-base-url" +) +def pubkeys(obj, account_id, nexus_base_url): + url = urljoin(nexus_base_url, "/ebics/subscribers/{}/pubkeys".format(account_id)) + + try: + response = get(url) + except Exception as e: + print("Could not reach nexus:", e) + return + + print(response.content.decode("utf-8")) + @ebics.command(help="Obtain passphrase-protected private keys") @click.pass_obj @click.option( diff --git a/util/src/main/kotlin/CryptoUtil.kt b/util/src/main/kotlin/CryptoUtil.kt @@ -115,6 +115,7 @@ object CryptoUtil { val tmp = RSAPublicKeySpec(modulusBigInt, exponentBigInt) return keyFactory.generatePublic(tmp) as RSAPublicKey } + /** * Hash an RSA public key according to the EBICS standard (EBICS 2.5: 4.4.1.2.3). */ @@ -126,6 +127,7 @@ object CryptoUtil { val digest = MessageDigest.getInstance("SHA-256") return digest.digest(keyBytes.toByteArray()) } + fun encryptEbicsE002(data: ByteArray, encryptionPublicKey: RSAPublicKey): EncryptionResult { val keygen = KeyGenerator.getInstance("AES", bouncyCastleProvider) keygen.init(128)