diff --git a/build.gradle.kts b/build.gradle.kts index fc741492..0269b222 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -148,7 +148,6 @@ dependencies { implementation("io.ktor:ktor-client-cio:$ktor_version") implementation("io.ktor:ktor-client-content-negotiation:$ktor_version") testImplementation("io.ktor:ktor-client-mock:$ktor_version") - implementation("tech.barbero.http-messages-signing:http-messages-signing-core:1.0.0") testImplementation("org.junit.jupiter:junit-jupiter:5.8.1") testImplementation("org.mockito.kotlin:mockito-kotlin:4.1.0") diff --git a/src/main/kotlin/dev/usbharu/hideout/config/HttpClientConfig.kt b/src/main/kotlin/dev/usbharu/hideout/config/HttpClientConfig.kt index 3332c81d..f25b2a4b 100644 --- a/src/main/kotlin/dev/usbharu/hideout/config/HttpClientConfig.kt +++ b/src/main/kotlin/dev/usbharu/hideout/config/HttpClientConfig.kt @@ -1,20 +1,16 @@ package dev.usbharu.hideout.config -import dev.usbharu.hideout.plugins.KtorKeyMap -import dev.usbharu.hideout.query.UserQueryService -import dev.usbharu.hideout.service.core.Transaction import io.ktor.client.* import io.ktor.client.engine.cio.* import io.ktor.client.plugins.cache.* import io.ktor.client.plugins.logging.* import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration -import tech.barbero.http.message.signing.KeyMap @Configuration class HttpClientConfig { @Bean - fun httpClient(keyMap: KeyMap): HttpClient = HttpClient(CIO).config { + fun httpClient(): HttpClient = HttpClient(CIO).config { install(Logging) { logger = Logger.DEFAULT level = LogLevel.INFO @@ -24,16 +20,4 @@ class HttpClientConfig { expectSuccess = true } - @Bean - fun keyMap( - userQueryService: UserQueryService, - transaction: Transaction, - applicationConfig: ApplicationConfig - ): KtorKeyMap { - return KtorKeyMap( - userQueryService, - transaction, - applicationConfig - ) - } } diff --git a/src/main/kotlin/dev/usbharu/hideout/plugins/ActivityPub.kt b/src/main/kotlin/dev/usbharu/hideout/plugins/ActivityPub.kt deleted file mode 100644 index 6b235333..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/plugins/ActivityPub.kt +++ /dev/null @@ -1,183 +0,0 @@ -package dev.usbharu.hideout.plugins - -import dev.usbharu.hideout.config.ApplicationConfig -import dev.usbharu.hideout.query.UserQueryService -import dev.usbharu.hideout.service.core.Transaction -import dev.usbharu.hideout.service.user.UserAuthServiceImpl -import io.ktor.client.plugins.api.* -import io.ktor.client.request.* -import io.ktor.http.* -import kotlinx.coroutines.runBlocking -import tech.barbero.http.message.signing.HttpMessage -import tech.barbero.http.message.signing.HttpMessageSigner -import tech.barbero.http.message.signing.HttpRequest -import tech.barbero.http.message.signing.KeyMap -import java.net.URI -import java.security.KeyFactory -import java.security.PrivateKey -import java.security.PublicKey -import java.security.spec.PKCS8EncodedKeySpec -import java.security.spec.X509EncodedKeySpec -import java.text.SimpleDateFormat -import java.util.* -import javax.crypto.SecretKey - -class HttpSignaturePluginConfig { - lateinit var keyMap: KeyMap -} - -val httpSignaturePlugin: ClientPlugin = createClientPlugin( - "HttpSign", - ::HttpSignaturePluginConfig -) { - val keyMap = pluginConfig.keyMap - val format = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US) - format.timeZone = TimeZone.getTimeZone("GMT") - onRequest { request, body -> - - request.header("Date", format.format(Date())) - request.header("Host", request.url.host) - if (request.bodyType?.type == String::class) { - body as String - -// UserAuthService.sha256.reset() - val digest = - Base64.getEncoder().encodeToString(UserAuthServiceImpl.sha256.digest(body.toByteArray(Charsets.UTF_8))) - request.headers.append("Digest", "sha-256=$digest") - } - - if (request.headers.contains("Signature")) { - val all = request.headers.getAll("Signature").orEmpty() - val parameters = mutableListOf() - for (s in all) { - s.split(",").forEach { parameters.add(it) } - } - - val keyId = parameters.find { it.startsWith("keyId") } - .orEmpty() - .split("=")[1] - .replace("\"", "") - val algorithm = - parameters.find { it.startsWith("algorithm") } - .orEmpty() - .split("=")[1] - .replace("\"", "") - val headers = parameters.find { it.startsWith("headers") } - .orEmpty() - .split("=")[1] - .replace("\"", "") - .split(" ") - .toMutableList() - - val algorithmType = when (algorithm) { - "rsa-sha256" -> { - HttpMessageSigner.Algorithm.RSA_SHA256 - } - - else -> { - TODO() - } - } - - headers.map { - when (it) { - "(request-target)" -> { - HttpMessageSigner.REQUEST_TARGET - } - - "digest" -> { - "Digest" - } - - "date" -> { - "Date" - } - - "host" -> { - "Host" - } - - else -> { - it - } - } - } - - val builder = HttpMessageSigner.builder().algorithm(algorithmType).keyId(keyId).keyMap(keyMap) - var tmp = builder - headers.forEach { - tmp = tmp.addHeaderToSign(it) - } - val signer = tmp.build() - - request.headers.remove("Signature") - - (signer ?: return@onRequest).sign(object : HttpMessage, HttpRequest { - override fun headerValues(name: String?): MutableList = - name?.let { request.headers.getAll(it) }?.toMutableList() ?: mutableListOf() - - override fun addHeader(name: String?, value: String?) { - val split = value?.split("=").orEmpty() - name?.let { request.header(it, split[0] + "=\"" + split[1].trim('"') + "\"") } - } - - override fun method(): String = request.method.value - - override fun uri(): URI = request.url.build().toURI() - }) - - val signatureHeader = request.headers.getAll("Signature").orEmpty() - request.headers.remove("Signature") - signatureHeader.joinToString(",") { it.replace("; ", ",").replace(";", ",") } - .let { request.header("Signature", it) } - } - } -} - -class KtorKeyMap( - private val userQueryService: UserQueryService, - private val transaction: Transaction, - private val applicationConfig: ApplicationConfig -) : KeyMap { - override fun getPublicKey(keyId: String?): PublicKey = runBlocking { - val username = (keyId ?: throw IllegalArgumentException("keyId is null")).substringBeforeLast("#pubkey") - .substringAfterLast("/") - val publicBytes = Base64.getDecoder().decode( - transaction.transaction { - userQueryService.findByNameAndDomain( - username, - applicationConfig.url.host - ).run { - publicKey - .replace("-----BEGIN PUBLIC KEY-----", "") - .replace("-----END PUBLIC KEY-----", "") - .replace("\n", "") - } - } - ) - val x509EncodedKeySpec = X509EncodedKeySpec(publicBytes) - return@runBlocking KeyFactory.getInstance("RSA").generatePublic(x509EncodedKeySpec) - } - - override fun getPrivateKey(keyId: String?): PrivateKey = runBlocking { - val username = (keyId ?: throw IllegalArgumentException("keyId is null")).substringBeforeLast("#pubkey") - .substringAfterLast("/") - val publicBytes = Base64.getDecoder().decode( - transaction.transaction { - userQueryService.findByNameAndDomain( - username, - applicationConfig.url.host - ).privateKey?.run { - replace("-----BEGIN PRIVATE KEY-----", "") - .replace("-----END PRIVATE KEY-----", "") - .replace("\n", "") - } - } - ) - val x509EncodedKeySpec = PKCS8EncodedKeySpec(publicBytes) - return@runBlocking KeyFactory.getInstance("RSA").generatePrivate(x509EncodedKeySpec) - } - - @Suppress("NotImplementedDeclaration") - override fun getSecretKey(keyId: String?): SecretKey = TODO("Not yet implemented") -} diff --git a/src/main/kotlin/dev/usbharu/hideout/service/auth/HttpSignatureVerifyService.kt b/src/main/kotlin/dev/usbharu/hideout/service/auth/HttpSignatureVerifyService.kt deleted file mode 100644 index f0009080..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/service/auth/HttpSignatureVerifyService.kt +++ /dev/null @@ -1,38 +0,0 @@ -package dev.usbharu.hideout.service.auth - -import dev.usbharu.hideout.config.ApplicationConfig -import dev.usbharu.hideout.plugins.KtorKeyMap -import dev.usbharu.hideout.query.UserQueryService -import dev.usbharu.hideout.service.core.Transaction -import io.ktor.http.* -import org.springframework.stereotype.Service -import tech.barbero.http.message.signing.SignatureHeaderVerifier - -@Service -interface HttpSignatureVerifyService { - fun verify(headers: Headers): Boolean -} - -@Service -class HttpSignatureVerifyServiceImpl( - private val userQueryService: UserQueryService, - private val transaction: Transaction, - private val applicationConfig: ApplicationConfig -) : HttpSignatureVerifyService { - override fun verify(headers: Headers): Boolean { - val build = - SignatureHeaderVerifier.builder().keyMap(KtorKeyMap(userQueryService, transaction, applicationConfig)) - .build() - return true -// build.verify(object : HttpMessage { -// override fun headerValues(name: String?): MutableList { -// return name?.let { headers.getAll(it) }?.toMutableList() ?: mutableListOf() -// } -// -// override fun addHeader(name: String?, value: String?) { -// TODO() -// } -// -// }) - } -} diff --git a/src/main/kotlin/dev/usbharu/hideout/service/signature/HttpSignatureSigner.kt b/src/main/kotlin/dev/usbharu/hideout/service/signature/HttpSignatureSigner.kt deleted file mode 100644 index f920f048..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/service/signature/HttpSignatureSigner.kt +++ /dev/null @@ -1,17 +0,0 @@ -package dev.usbharu.hideout.service.signature - -import io.ktor.http.* - -interface HttpSignatureSigner { - @Suppress("LongParameterList") - suspend fun sign( - url: String, - method: HttpMethod, - headers: Headers, - requestBody: String, - keyPair: Key, - signHeaders: List - ): SignedRequest - - suspend fun signRaw(signString: String, keyPair: Key, signHeaders: List): Sign -} diff --git a/src/main/kotlin/dev/usbharu/hideout/service/signature/HttpSignatureSignerImpl.kt b/src/main/kotlin/dev/usbharu/hideout/service/signature/HttpSignatureSignerImpl.kt deleted file mode 100644 index 193658ba..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/service/signature/HttpSignatureSignerImpl.kt +++ /dev/null @@ -1,84 +0,0 @@ -package dev.usbharu.hideout.service.signature - -import dev.usbharu.hideout.util.Base64Util -import io.ktor.http.* -import io.ktor.util.* -import org.springframework.stereotype.Component -import java.net.URL -import java.security.Signature - -@Component -class HttpSignatureSignerImpl : HttpSignatureSigner { - override suspend fun sign( - url: String, - method: HttpMethod, - headers: Headers, - requestBody: String, - keyPair: Key, - signHeaders: List - ): SignedRequest { - val sign = signRaw( - signString = buildSignString( - url = URL(url), - method = method, - headers = headers, - signHeaders = signHeaders - ), - keyPair = keyPair, - signHeaders = signHeaders - ) - val signedHeaders = headers { - appendAll(headers) - set("Signature", sign.signatureHeader) - } - return SignedRequest( - url = url, - method = method, - headers = signedHeaders, - requestBody = requestBody, - sign = sign - ) - } - - override suspend fun signRaw(signString: String, keyPair: Key, signHeaders: List): Sign { - val signer = Signature.getInstance("SHA256withRSA") - signer.initSign(keyPair.privateKey) - signer.update(signString.toByteArray()) - val sign = signer.sign() - val signature = Base64Util.encode(sign) - return Sign( - signature, - """keyId="${keyPair.keyId}",algorithm="rsa-sha256",headers="${ - signHeaders.joinToString( - " " - ) - }",signature="$signature"""" - ) - } - - private fun buildSignString( - url: URL, - method: HttpMethod, - headers: Headers, - signHeaders: List - ): String { - headers.toMap().map { it.key.lowercase() to it.value }.toMap() - val result = signHeaders.joinToString("\n") { - if (it.startsWith("(")) { - specialHeader(it, url, method) - } else { - generalHeader(it, headers.get(it)!!) - } - } - return result - } - - private fun specialHeader(fieldName: String, url: URL, method: HttpMethod): String { - if (fieldName != "(request-target)") { - throw IllegalArgumentException(fieldName + "is unsupported type") - } - return "(request-target): ${method.value.lowercase()} ${url.path}" - } - - private fun generalHeader(fieldName: String, value: String): String = "$fieldName: $value" -} diff --git a/src/main/kotlin/dev/usbharu/hideout/service/signature/Key.kt b/src/main/kotlin/dev/usbharu/hideout/service/signature/Key.kt deleted file mode 100644 index 0eb5171f..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/service/signature/Key.kt +++ /dev/null @@ -1,10 +0,0 @@ -package dev.usbharu.hideout.service.signature - -import java.security.PrivateKey -import java.security.PublicKey - -data class Key( - val keyId: String, - val privateKey: PrivateKey, - val publicKey: PublicKey -) diff --git a/src/main/kotlin/dev/usbharu/hideout/service/signature/Sign.kt b/src/main/kotlin/dev/usbharu/hideout/service/signature/Sign.kt deleted file mode 100644 index 75711759..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/service/signature/Sign.kt +++ /dev/null @@ -1,6 +0,0 @@ -package dev.usbharu.hideout.service.signature - -data class Sign( - val signature: String, - val signatureHeader: String -) diff --git a/src/main/kotlin/dev/usbharu/hideout/service/signature/SignedRequest.kt b/src/main/kotlin/dev/usbharu/hideout/service/signature/SignedRequest.kt deleted file mode 100644 index 346dca87..00000000 --- a/src/main/kotlin/dev/usbharu/hideout/service/signature/SignedRequest.kt +++ /dev/null @@ -1,23 +0,0 @@ -package dev.usbharu.hideout.service.signature - -import io.ktor.client.request.* -import io.ktor.http.* - -data class SignedRequest( - val url: String, - val method: HttpMethod, - val headers: Headers, - val requestBody: String, - val sign: Sign -) { - fun toRequestBuilder(): HttpRequestBuilder { - val httpRequestBuilder = HttpRequestBuilder() - httpRequestBuilder.url(this.url) - httpRequestBuilder.method = this.method - httpRequestBuilder.headers { - this.appendAll(headers) - } - httpRequestBuilder.setBody(requestBody) - return httpRequestBuilder - } -} diff --git a/src/test/kotlin/dev/usbharu/hideout/plugins/KtorKeyMapTest.kt b/src/test/kotlin/dev/usbharu/hideout/plugins/KtorKeyMapTest.kt deleted file mode 100644 index 6eeca290..00000000 --- a/src/test/kotlin/dev/usbharu/hideout/plugins/KtorKeyMapTest.kt +++ /dev/null @@ -1,44 +0,0 @@ -package dev.usbharu.hideout.plugins - -import dev.usbharu.hideout.domain.model.hideout.entity.User -import dev.usbharu.hideout.query.UserQueryService -import dev.usbharu.hideout.service.user.toPem -import org.junit.jupiter.api.Test -import org.mockito.kotlin.any -import org.mockito.kotlin.doAnswer -import org.mockito.kotlin.mock -import utils.TestApplicationConfig.testApplicationConfig -import utils.TestTransaction -import java.security.KeyPairGenerator -import java.time.Instant - -class KtorKeyMapTest { - - @Test - fun getPrivateKey() { - val userQueryService = mock { - onBlocking { findByNameAndDomain(any(), any()) } doAnswer { - val keyPairGenerator = KeyPairGenerator.getInstance("RSA") - keyPairGenerator.initialize(1024) - val generateKeyPair = keyPairGenerator.generateKeyPair() - User.of( - 1, - "test", - "localhost", - "test", - "", - "", - "https://example.com/inbox", - "https://example.com/outbox", - "https://example.com", - "", - generateKeyPair.private.toPem(), - createdAt = Instant.now() - ) - } - } - val ktorKeyMap = KtorKeyMap(userQueryService, TestTransaction, testApplicationConfig) - - ktorKeyMap.getPrivateKey("test") - } -} diff --git a/src/test/kotlin/dev/usbharu/hideout/service/signature/HttpSignatureSignerImplTest.kt b/src/test/kotlin/dev/usbharu/hideout/service/signature/HttpSignatureSignerImplTest.kt deleted file mode 100644 index 09c006db..00000000 --- a/src/test/kotlin/dev/usbharu/hideout/service/signature/HttpSignatureSignerImplTest.kt +++ /dev/null @@ -1,340 +0,0 @@ -package dev.usbharu.hideout.service.signature - -import dev.usbharu.hideout.util.Base64Util -import dev.usbharu.hideout.util.RsaUtil -import io.ktor.http.* -import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.Test -import tech.barbero.http.message.signing.HttpMessage -import tech.barbero.http.message.signing.HttpRequest -import tech.barbero.http.message.signing.KeyMap -import tech.barbero.http.message.signing.SignatureHeaderVerifier -import java.net.URI -import java.net.URL -import java.security.MessageDigest -import java.security.PrivateKey -import java.security.PublicKey -import java.text.SimpleDateFormat -import java.time.ZoneId -import java.time.ZonedDateTime -import java.time.format.DateTimeFormatter -import java.util.* -import javax.crypto.SecretKey -import kotlin.test.assertFalse - -class HttpSignatureSignerImplTest { - @Test - fun `HTTP Signatureの署名を作成できる`() = runTest { - - val publicKey = RsaUtil.decodeRsaPublicKey( - """MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv6tEMdAw9xk3Pt5YMxJ2t+1QZeb9p+PKpS1lVbkL5oWj6aL2Q3nRVQQabcILOb5YNUpWQVQWRjW4jkrBDuiAgvlmu126OPs4E1cVVWEqylJ5VOkOIeXpldOu/SvHM/sHPNHXYlovaHDIqT+3zp2xUmXQx2kum0b/o8Vp+wh45iIoflb62/0dQ5YZyZEp283XKne+u813BzCOa1IAsywbUvX9kUv1SaUDn3oxnjdjWgSqsJcJVU1lyiN0OrpnEg5TMVjDqN3vimoR4uqNn5Zm8rrif/o8w+/FlnWticbty5MQun0gFaCfLsR8ODm1/0DwT6WI/bRpy6zye1n4iQn/nwIDAQAB""" - ) - val privateKey = RsaUtil.decodeRsaPrivateKey( - """MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC/q0Qx0DD3GTc+3lgzEna37VBl5v2n48qlLWVVuQvmhaPpovZDedFVBBptwgs5vlg1SlZBVBZGNbiOSsEO6ICC+Wa7Xbo4+zgTVxVVYSrKUnlU6Q4h5emV0679K8cz+wc80ddiWi9ocMipP7fOnbFSZdDHaS6bRv+jxWn7CHjmIih+Vvrb/R1DlhnJkSnbzdcqd767zXcHMI5rUgCzLBtS9f2RS/VJpQOfejGeN2NaBKqwlwlVTWXKI3Q6umcSDlMxWMOo3e+KahHi6o2flmbyuuJ/+jzD78WWda2Jxu3LkxC6fSAVoJ8uxHw4ObX/QPBPpYj9tGnLrPJ7WfiJCf+fAgMBAAECggEAIkL4LrtbdWAxivBt7bs4M4qdW4nd/9vtRneF7LvmT6/F7CawRMGK1Nql6sbMAOdwlx4Rqx3f2W8S7YSZXBPdnQv9/DI17qehj3t6mceDwaTagX4jg5W4moq7dhAUTMtrsMiF6tPaM54tkGuObMWtg+AlYPABX8piOiE436HVErXrOaWsrQ6ReoHodTyibfO8aByzLkIb2k3nt1j8HotjjFe6ZqFVkXiGVWOUwdLpsqE+8BV6g1IF480SyKF4HnUfr/AxDnpKtTFspGCKu/w7BA6yOaaONeal0/EUA8vlfLsKdaRY2TRmCFCQzUwluBTr6ssjQyilJzgJ6VbDFpVSSQKBgQDgpt5kB7TDXN5ucD0alN0umI/rLD5TTg0rbpLo2wzfh2IAPYSiCgNOVr1Mi6JRxqSLa4KeEOCYATLu9wrFU8y+i/ffrDAMo/b2z3TORV3p3m1fPx6CnqBZMvxrHl2CCbij+6O1qmq+8AW8+lQuilq3u6dRBkYpt+mRHWsqvMeNqwKBgQDaair8CIEcoCtxlw8lDRJNn7bC9DRiaJLxPYuOHop7lolUy1amd2srREgoEB7FRwC5bki+BsSUffFyix2kUsf4I2dLHYmbf4Aci2GpqdRW4AnO2tWnvHGsAnkmsRQ2ZuoF7+8Phd1pnXY9DHImAxmpUgqhKDqbP4Hi1W2w5s0Z3QKBgQCTlUxYTq+0AFioGNgrlExSBivWBXTUaVxBghzFGNK2Lkx1d/SgNw/A8T7fAIScUHFcnj5q9Q93DKKXVnge9lR1gaJPsODIDRd7QQKtV+jAcT1M6zxx9x/EObiV7pbjjNtd7zy3ZcNGuIwsgA+5m27JcWAT3JlPYuDwUnFK3EYEjQKBgCHCm1ZNsjdMgqqSIOMnPBcHguZrfNVhOKVVUAbtrZYg1KVosMIWX1hWu5iFtVvk97Wx2EiXHzecp/9+hVxq90HhpwuzSxvf/1tqJ/RjrdCn3Jw+sxu0QxXFZBiY8njeO3ojdh4+INU8Y5RYIiTCAetsJPx4DWcFz/vR5ZyccEN5AoGAHgP5ZeUvn/NR5GvX7NIVbYReO6+YeilNE8mGa57Ew4GJotrS5P4nevDyZWZCs63f4ZQ/I/lJnrGRtQDfQC7wUGhMf7VjZfagFHcSO44uCVKsSO7ToTyuObTpdEC9dUeVaJt96ZP5eX4vWZ6MNgYstlmXKVLg9LHsLJlXKNHufg0=""" - ) - - val httpSignatureSignerImpl = HttpSignatureSignerImpl() - - val format = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US) - format.timeZone = TimeZone.getTimeZone("GMT") - - //language=JSON - val requestBody = """{ - "hoge": "fuga" -}""" - - val sha256 = MessageDigest.getInstance("SHA-256") - - val encode = Base64Util.encode(sha256.digest(requestBody.toByteArray())) - - val url = "https://example.com/" - httpSignatureSignerImpl.sign( - url, - HttpMethod.Post, - Headers.build { - append("Date", "Fri, 13 Oct 2023 07:14:50 GMT") - append("Host", URL(url).host) - append("Digest", "SHA-256=$encode") - }, - requestBody, - Key("https://example.com", privateKey, publicKey), - listOf("(request-target)", "date", "host", "digest") - ) - } - - @Test - fun `HTTP Signatureの署名が検証に成功する`() = runTest { - val publicKey = RsaUtil.decodeRsaPublicKey( - """MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuJVqbb17nCo8aBZYF+vDgnFANaFDNuvHKMT39qQGnetItYZ8DBtRZzvYE6njn1vH7gixPhGnjt6qLWJJzeoSSv1FgQp9yUq719QFC9BQ87RughpkrP1Nq0ZHuTLMH0U13g2oziRp04FZXElq6b3aHLK+Y78mX20l9HCqIh4GdBRjgiAjcZr/XOZl1cKa7ai3z4yO4euOb8LiJavMHz7/ISefUGtikrhnIqNwwQ1prxT1bZduTotjSi8bitdzsvGh5ftTiFxJC+Pe1yJn3ALW/L3SBm72x60S14osQv1gMaDLaA6YNXCYm34xKndF+UxWTUwLUpNM/GRDoNa8Yq7HBwIDAQAB""" - ) - val privateKey = RsaUtil.decodeRsaPrivateKey( - """MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC4lWptvXucKjxoFlgX68OCcUA1oUM268coxPf2pAad60i1hnwMG1FnO9gTqeOfW8fuCLE+EaeO3qotYknN6hJK/UWBCn3JSrvX1AUL0FDztG6CGmSs/U2rRke5MswfRTXeDajOJGnTgVlcSWrpvdocsr5jvyZfbSX0cKoiHgZ0FGOCICNxmv9c5mXVwprtqLfPjI7h645vwuIlq8wfPv8hJ59Qa2KSuGcio3DBDWmvFPVtl25Oi2NKLxuK13Oy8aHl+1OIXEkL497XImfcAtb8vdIGbvbHrRLXiixC/WAxoMtoDpg1cJibfjEqd0X5TFZNTAtSk0z8ZEOg1rxirscHAgMBAAECggEAU5VRQs09Rpt3jBimHnrjptM6pK5X/ewpXKRItpZS6rqqy4xQ6riKFYmrUEgrazOH5ploDTe4XMEmZXOvAP/f9bYXfZXvHLHrOpHnERDtP1XyfpaOBSmUvJyQCORgOz6/ZERiLqqdgyl8+gXC1IJkXH9yKD/cE/UcbUKBP/7BpFj7lPMyNCApiS1Z2RinvOSsx2TCBfVLpEE1dTLdHg3g3vfkmnn+KQ/SU4z3ksXJa0ODZY9lsUGWUrGmnhd/tviSuNUJG3wx7h1er4LBjuA4OZD8qJA+sXcEY2Kn7XQHAOBWUfAOR7nzAl3mPYycIZs4sDrq2awwX12ML9qR/40swQKBgQDtBhIML+Xt32fLw4/wtSDmDJo4szyu0c3Gangl4eMjOc1WEXl/bL8uryNS9b+1he8b+VgEBFH2nhl3u1eman0/xpk9hqj9hd/IDazMqUr7mKq+b9WXWd24LFZNew+35RUELW01FdEDSr+KZsCIjFilAeWfpJORoj3oZFU5C/5mQQKBgQDHXI7NqHy2ATqDiQI3aG72B8n3TbR9B8G01Anfn3ZKcXIFWnDHoB9y/ITYzGrjrbbEOD2BsAacOy7bOWHlX1RIcD10ZWJIBdjqc+zfpahb36mXbcEQkb7col5s992KGVZHu8OBwfGJMVHYprIxOmygj1CAF9pEZyMy3alHChOrRwKBgQCYeyxHHNVNh0huBLxn/Q5SEM9yJJSoXp6Dw+DRdhU6hyf687j26c3ASblu2Fvhem1N0MX3p5PXFPSLW0FS9PTof2n789JpbqN9Ppbo/wwW+ar2YlnFSXHi1tsac020XzJ7AoJcAVH6TS8V6W55KdipJqRDZIvux7IN++X7kiSyQQKBgQCweIIAEhCym0vMe0729P6j0ik5PBN0SZVyF+/VfzYal2kyy+fhDSBJjLWbovdLKs4Jyy7GyaZQTSMg8x5xB3130cLUcZoZ3vMwNgWLwvvQt59LZ9/qZtjoPOIQ2yfDwsHZJZ/eEGtZ4cptWMGLSgg16CZ9/J88xX8m24eoVocqqQKBgCEj/FK26bBLnPtRlQ+5mTQ/CjcjD5/KoaHLawULvXq03qIiZfDZg+sm7JUmlaC48sERGLJnjNYk/1pjw5N8txyAk2UHxqi+dayRkTCRSfBm0PUWyVWiperHNEuByHnyh+qX00sE3SCz2qDSDLb1x7kV+2BhEL+XfgD7evqrvrNq""" - ) - - val httpSignatureSignerImpl = HttpSignatureSignerImpl() - - val format = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US) - format.timeZone = TimeZone.getTimeZone("GMT") - - //language=JSON - val requestBody = """{ - "hoge": "fuga" -}""" - - val sha256 = MessageDigest.getInstance("SHA-256") - - val encode = Base64Util.encode(sha256.digest(requestBody.toByteArray())) - - val url = "https://example.com/" - val headers = Headers.build { - append("Date", "Fri, 13 Oct 2023 07:14:50 GMT") - append("Host", URL(url).host) - append("Digest", "SHA-256=$encode") - } - val sign = httpSignatureSignerImpl.sign( - url, - HttpMethod.Post, - headers, - requestBody, - Key("https://example.com", privateKey, publicKey), - listOf("(request-target)", "date", "host", "digest") - ) - - val keyMap = object : KeyMap { - override fun getPublicKey(keyId: String?): PublicKey { - return publicKey - } - - override fun getPrivateKey(keyId: String?): PrivateKey { - return privateKey - } - - override fun getSecretKey(keyId: String?): SecretKey { - TODO("Not yet implemented") - } - - } - val verifier = SignatureHeaderVerifier.builder().keyMap(keyMap).build() - - val headers1 = headers { - appendAll(headers) - append("Signature", sign.sign.signatureHeader) - } - - val httpMessage = object : HttpMessage, HttpRequest { - override fun headerValues(name: String?): MutableList { - return name?.let { headers1.getAll(it) }.orEmpty().toMutableList() - } - - override fun addHeader(name: String?, value: String?) { - TODO("Not yet implemented") - } - - override fun method(): String { - return "POST" - } - - override fun uri(): URI { - return URI(url) - } - } - val verify = verifier.verify(httpMessage) - assertTrue(verify) - } - - @Test - fun `HTTP Signatureの署名が検証に成功する2`() = runTest { - val publicKey = RsaUtil.decodeRsaPublicKeyPem( - """-----BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq3YdxpopDvAIp+Ciplvx -SfY8tV3GquYIfxSfTPAqiusgf8zXxYz0ilxY+nHjzIpdOA8rDHcDVhBXI/5lP1Vl -sgeY5cgJRuG9g9ZWaQV/8oKYoillgTkNuyNB0OGa84BAeKo+VMG1NNtlVCn2DrvA -8FLXAc2e4wPcOozKV5JYHZ0RDcSIS1bPb5ArxhhF8zAjn9+s/plsDz+mgHD0Ce5z -UUv1uHQF8nj53WL4cCcrl5TSvqaK6Krcmb7i1YVSlk52p0AYg79pXpPQLhe3TnvJ -Gy+KPvKPq1cho5jM1vJktK6eGlnUPEgD0bCSXl7FrtE7mPMCsaQCRj+up4t+NBWu -gwIDAQAB ------END PUBLIC KEY-----""" - ) - val privateKey = RsaUtil.decodeRsaPrivateKeyPem( - """-----BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCrdh3GmikO8Ain -4KKmW/FJ9jy1Xcaq5gh/FJ9M8CqK6yB/zNfFjPSKXFj6cePMil04DysMdwNWEFcj -/mU/VWWyB5jlyAlG4b2D1lZpBX/ygpiiKWWBOQ27I0HQ4ZrzgEB4qj5UwbU022VU -KfYOu8DwUtcBzZ7jA9w6jMpXklgdnRENxIhLVs9vkCvGGEXzMCOf36z+mWwPP6aA -cPQJ7nNRS/W4dAXyePndYvhwJyuXlNK+poroqtyZvuLVhVKWTnanQBiDv2lek9Au -F7dOe8kbL4o+8o+rVyGjmMzW8mS0rp4aWdQ8SAPRsJJeXsWu0TuY8wKxpAJGP66n -i340Fa6DAgMBAAECggEAUsE0h9l5/aKumtAZ0K9JmwgErwiuzWcvLJ64cDruXZQ0 -YFpuvgNVN75wl5gGeX9ClL8FaQO8EXrbhBzRoyrFZZKzIhxVFef4PzxhAllMMrED -mCjgu+jcjrjqmDV7QxFgjJymbuP7YKKPmnqSLvRBn/xrl4w1pp4DWiL/uhqA+vE8 -ZOgfzJ6LzU3CUFjCEi73gfZzTyykzpw+H3Lf8WPYCRQteng7zGxFDpPM3uDt0AKV -nTReopN6HKVOqobBuJLbD2kORfFzfzfLKrkAELivO/yOdosbG5GIf8nxZ0h86QIo -knav6boRgF9LqZTzC+QWBjGXEng58gEYEuAaovup8QKBgQDeR9onVIj67FZ/J1k4 -VBTfxRZ4r2oFHyhh3O2Y1xmVM0ejlvtnQL989d6HCieT6wd9CcfTOnTidgXCW+1a -wW3Q6eqtaPanRsU8aCcG2Pa19hbEkdsAvu/8eS8SWegnyqk0lKZjRP6KXDto99dd -CWs8KMcTXTqpFfNr83AeuR1ViwKBgQDFeLms7hvnLVF0oS6LIh73WVd1YfhcCsxo -MfjLmsivCfvyo/RAWmWjHTvh9ofYm3a/1gU4ACm33tI++uWz1juHxJFy+ryjjz7z -MHimmohaWkeax9wyUn66hG52JYUHQFoi85cL/YLMMX3WZXa5LQyyXPgirF4L9+c9 -MTZNrKDZ6QKBgEhDX77NksLQtsYbyruvSiH9dvLBRFxp5rz6EBxSQbTpuO6MFSta -N2auoCuSt481J3gVB+u542oEKJcpP57zp3n1sh+yMg3ryg97ZMSrIHnDiV9ac7Jo -YKjZ1N3IcNsO3beEZBt9wKrGlWHowRE0ELK8Jww6kOmLg1mjCN5UHB9FAoGAVewl -vl0MvxY07y6C9f8uwimZqHWsf0AjmOLFgrIiyCbr/bPhP28V8ldyCuweR929WdNi -Ce/oNx05FjZNZGa/GGAreYAoPHLDzUU1+igbVFUb+vkjkrHaeoXNGpNQwsr5bWPY -QVtZYkfWnUcg1YoIkENrpIqjkUmY0ENtgXavtqECgYEA2F+FJPPpm39gD2mnbnAH -goM9c+h9hh/o3kW3CUNgPKeYT4ptd3AG0k9C9De+eWb3GGqH1/KUGvUbyXm7f1Wi -y+SBT1Uk6/85ZZ3nCz2Yj8eGokhcfKhXd8K3HV2wgoUWMJT1Qvedrqc2R5S9wdY8 -wADggCG8df/amNR+dyQOOuQ= ------END PRIVATE KEY-----""" - ) - - val httpSignatureSignerImpl = HttpSignatureSignerImpl() - - val format = DateTimeFormatter.RFC_1123_DATE_TIME - - //language=JSON - val requestBody = """{ - "hoge": "fuga" -}""" - - val sha256 = MessageDigest.getInstance("SHA-256") - - val encode = Base64Util.encode(sha256.digest(requestBody.toByteArray())) - - val url = "https://test-hideout.usbharu.dev/users/97ws8y3rj6/inbox" - val headers = Headers.build { - append("Date", format.format(ZonedDateTime.now(ZoneId.of("GMT")))) - append("Host", URL(url).host) - append("Digest", "sha-256=$encode") - } - val sign = httpSignatureSignerImpl.sign( - url, - HttpMethod.Post, - headers, - requestBody, - Key("https://test-hideout.usbharu.dev/users/c#pubkey", privateKey, publicKey), - listOf("(request-target)", "date", "host", "digest") - ) - - val keyMap = object : KeyMap { - override fun getPublicKey(keyId: String?): PublicKey { - return publicKey - } - - override fun getPrivateKey(keyId: String?): PrivateKey { - return privateKey - } - - override fun getSecretKey(keyId: String?): SecretKey { - TODO("Not yet implemented") - } - - } - val verifier = SignatureHeaderVerifier.builder().keyMap(keyMap).build() - - val headers1 = headers { - appendAll(headers) - append("Signature", sign.sign.signatureHeader) - } - - val httpMessage = object : HttpMessage, HttpRequest { - override fun headerValues(name: String?): MutableList { - return name?.let { headers1.getAll(it) }.orEmpty().toMutableList() - } - - override fun addHeader(name: String?, value: String?) { - TODO("Not yet implemented") - } - - override fun method(): String { - return "POST" - } - - override fun uri(): URI { - return URI(url) - } - } - val verify = verifier.verify(httpMessage) - assertTrue(verify) - } - - @Test - fun `HTTP Signatureで署名した後、改ざんされた場合検証に失敗する`() = runTest { - val publicKey = RsaUtil.decodeRsaPublicKey( - """MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuJVqbb17nCo8aBZYF+vDgnFANaFDNuvHKMT39qQGnetItYZ8DBtRZzvYE6njn1vH7gixPhGnjt6qLWJJzeoSSv1FgQp9yUq719QFC9BQ87RughpkrP1Nq0ZHuTLMH0U13g2oziRp04FZXElq6b3aHLK+Y78mX20l9HCqIh4GdBRjgiAjcZr/XOZl1cKa7ai3z4yO4euOb8LiJavMHz7/ISefUGtikrhnIqNwwQ1prxT1bZduTotjSi8bitdzsvGh5ftTiFxJC+Pe1yJn3ALW/L3SBm72x60S14osQv1gMaDLaA6YNXCYm34xKndF+UxWTUwLUpNM/GRDoNa8Yq7HBwIDAQAB""" - ) - val privateKey = RsaUtil.decodeRsaPrivateKey( - """MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC4lWptvXucKjxoFlgX68OCcUA1oUM268coxPf2pAad60i1hnwMG1FnO9gTqeOfW8fuCLE+EaeO3qotYknN6hJK/UWBCn3JSrvX1AUL0FDztG6CGmSs/U2rRke5MswfRTXeDajOJGnTgVlcSWrpvdocsr5jvyZfbSX0cKoiHgZ0FGOCICNxmv9c5mXVwprtqLfPjI7h645vwuIlq8wfPv8hJ59Qa2KSuGcio3DBDWmvFPVtl25Oi2NKLxuK13Oy8aHl+1OIXEkL497XImfcAtb8vdIGbvbHrRLXiixC/WAxoMtoDpg1cJibfjEqd0X5TFZNTAtSk0z8ZEOg1rxirscHAgMBAAECggEAU5VRQs09Rpt3jBimHnrjptM6pK5X/ewpXKRItpZS6rqqy4xQ6riKFYmrUEgrazOH5ploDTe4XMEmZXOvAP/f9bYXfZXvHLHrOpHnERDtP1XyfpaOBSmUvJyQCORgOz6/ZERiLqqdgyl8+gXC1IJkXH9yKD/cE/UcbUKBP/7BpFj7lPMyNCApiS1Z2RinvOSsx2TCBfVLpEE1dTLdHg3g3vfkmnn+KQ/SU4z3ksXJa0ODZY9lsUGWUrGmnhd/tviSuNUJG3wx7h1er4LBjuA4OZD8qJA+sXcEY2Kn7XQHAOBWUfAOR7nzAl3mPYycIZs4sDrq2awwX12ML9qR/40swQKBgQDtBhIML+Xt32fLw4/wtSDmDJo4szyu0c3Gangl4eMjOc1WEXl/bL8uryNS9b+1he8b+VgEBFH2nhl3u1eman0/xpk9hqj9hd/IDazMqUr7mKq+b9WXWd24LFZNew+35RUELW01FdEDSr+KZsCIjFilAeWfpJORoj3oZFU5C/5mQQKBgQDHXI7NqHy2ATqDiQI3aG72B8n3TbR9B8G01Anfn3ZKcXIFWnDHoB9y/ITYzGrjrbbEOD2BsAacOy7bOWHlX1RIcD10ZWJIBdjqc+zfpahb36mXbcEQkb7col5s992KGVZHu8OBwfGJMVHYprIxOmygj1CAF9pEZyMy3alHChOrRwKBgQCYeyxHHNVNh0huBLxn/Q5SEM9yJJSoXp6Dw+DRdhU6hyf687j26c3ASblu2Fvhem1N0MX3p5PXFPSLW0FS9PTof2n789JpbqN9Ppbo/wwW+ar2YlnFSXHi1tsac020XzJ7AoJcAVH6TS8V6W55KdipJqRDZIvux7IN++X7kiSyQQKBgQCweIIAEhCym0vMe0729P6j0ik5PBN0SZVyF+/VfzYal2kyy+fhDSBJjLWbovdLKs4Jyy7GyaZQTSMg8x5xB3130cLUcZoZ3vMwNgWLwvvQt59LZ9/qZtjoPOIQ2yfDwsHZJZ/eEGtZ4cptWMGLSgg16CZ9/J88xX8m24eoVocqqQKBgCEj/FK26bBLnPtRlQ+5mTQ/CjcjD5/KoaHLawULvXq03qIiZfDZg+sm7JUmlaC48sERGLJnjNYk/1pjw5N8txyAk2UHxqi+dayRkTCRSfBm0PUWyVWiperHNEuByHnyh+qX00sE3SCz2qDSDLb1x7kV+2BhEL+XfgD7evqrvrNq""" - ) - - val httpSignatureSignerImpl = HttpSignatureSignerImpl() - - val format = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US) - format.timeZone = TimeZone.getTimeZone("GMT") - - //language=JSON - val requestBody = """{ - "hoge": "fuga" -}""" - - val sha256 = MessageDigest.getInstance("SHA-256") - - val encode = Base64Util.encode(sha256.digest(requestBody.toByteArray())) - - val url = "https://example.com/" - val headers = Headers.build { - append("Date", "Fri, 13 Oct 2023 07:14:50 GMT") - append("Host", URL(url).host) - append("Digest", "SHA-256=$encode") - } - val sign = httpSignatureSignerImpl.sign( - url, - HttpMethod.Post, - headers, - requestBody, - Key("https://example.com", privateKey, publicKey), - listOf("(request-target)", "date", "host", "digest") - ) - - val keyMap = object : KeyMap { - override fun getPublicKey(keyId: String?): PublicKey { - return publicKey - } - - override fun getPrivateKey(keyId: String?): PrivateKey { - return privateKey - } - - override fun getSecretKey(keyId: String?): SecretKey { - TODO("Not yet implemented") - } - - } - val verifier = SignatureHeaderVerifier.builder().keyMap(keyMap).build() - - val headers1 = headers { - appendAll(headers) - append("Signature", sign.sign.signatureHeader) - set("Digest", "aaaaaaaaaaaaaaaaafsadasfgafaaaaaaaaaaa") - } - - val httpMessage = object : HttpMessage, HttpRequest { - override fun headerValues(name: String?): MutableList { - return name?.let { headers1.getAll(it) }.orEmpty().toMutableList() - } - - override fun addHeader(name: String?, value: String?) { - TODO("Not yet implemented") - } - - override fun method(): String { - return "POST" - } - - override fun uri(): URI { - return URI(url) - } - } - val verify = verifier.verify(httpMessage) - assertFalse(verify) - } -}