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:
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)