-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Properly X.509 encode RSA signatures imported from raw bytes (#196)
- Loading branch information
1 parent
5829f99
commit f79ecf3
Showing
10 changed files
with
293 additions
and
107 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
113 changes: 113 additions & 0 deletions
113
indispensable/src/jvmTest/kotlin/at/asitplus/signum/indispensable/SignatureCodecTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package at.asitplus.signum.indispensable | ||
|
||
import at.asitplus.signum.indispensable.pki.getContentSigner | ||
import io.kotest.core.spec.style.FreeSpec | ||
import io.kotest.datatest.withData | ||
import io.kotest.matchers.shouldBe | ||
import org.bouncycastle.asn1.ASN1Sequence | ||
import org.bouncycastle.asn1.DLSequence | ||
import org.bouncycastle.asn1.x500.X500Name | ||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo | ||
import org.bouncycastle.cert.X509v3CertificateBuilder | ||
import org.bouncycastle.jce.provider.BouncyCastleProvider | ||
import org.bouncycastle.operator.ContentSigner | ||
import java.math.BigInteger | ||
import java.security.KeyPair | ||
import java.security.KeyPairGenerator | ||
import java.security.Security | ||
import java.security.Signature | ||
import java.security.spec.ECGenParameterSpec | ||
import java.time.Instant | ||
import java.util.* | ||
import kotlin.math.absoluteValue | ||
import kotlin.random.Random | ||
import kotlin.time.Duration.Companion.days | ||
|
||
@OptIn(ExperimentalStdlibApi::class) | ||
class SignatureCodecTest : FreeSpec({ | ||
|
||
"EC" - { | ||
val curve = "secp256r1" | ||
val digest = "SHA256" | ||
val data = Random.nextBytes(256) | ||
|
||
val preGen = List<KeyPair>(500) { | ||
KeyPairGenerator.getInstance("EC").also { | ||
it.initialize(ECGenParameterSpec(curve)) | ||
}.generateKeyPair() | ||
} | ||
withData(nameFn = { CryptoPublicKey.fromJcaPublicKey(it.public).getOrThrow().didEncoded }, preGen) { keys -> | ||
val sig = Signature.getInstance("${digest}withECDSA").run { | ||
initSign(keys.private) | ||
update(data) | ||
sign() | ||
} | ||
|
||
CryptoSignature.EC.parseFromJca(sig).jcaSignatureBytes shouldBe sig | ||
CryptoSignature.parseFromJca( | ||
sig, | ||
SignatureAlgorithm.ECDSA(Digest.valueOf(digest), ECCurve.byJcaName(curve)) | ||
).jcaSignatureBytes shouldBe sig | ||
|
||
Signature.getInstance("${digest}withECDSAinP1363Format").run { | ||
initVerify(keys.public) | ||
update(data) | ||
verify(CryptoSignature.EC.parseFromJca(sig).encodeToDer()) | ||
} | ||
|
||
} | ||
} | ||
|
||
"RSA" - { | ||
Security.addProvider(BouncyCastleProvider()) | ||
|
||
val digest = ("SHA256") | ||
|
||
val preGen = List(500) { KeyPairGenerator.getInstance("RSA").apply { initialize(512) }.generateKeyPair() } | ||
withData(nameFn = { CryptoPublicKey.fromJcaPublicKey(it.public).getOrThrow().didEncoded }, preGen) { keys -> | ||
val data = Random.nextBytes(256) | ||
val sig = Signature.getInstance("${digest}withRSA").run { | ||
initSign(keys.private) | ||
update(data) | ||
sign() | ||
} | ||
|
||
CryptoSignature.RSAorHMAC.parseFromJca(sig).jcaSignatureBytes shouldBe sig | ||
CryptoSignature.parseFromJca( | ||
sig, | ||
SignatureAlgorithm.RSA(Digest.valueOf(digest), RSAPadding.PKCS1) | ||
).jcaSignatureBytes shouldBe sig | ||
|
||
// create certificate with bouncycastle | ||
val notBeforeDate = Date.from(Instant.now()) | ||
val notAfterDate = Date.from(Instant.now().plusSeconds(30.days.inWholeSeconds)) | ||
val serialNumber: BigInteger = BigInteger.valueOf(Random.nextLong().absoluteValue) | ||
val commonName = "DefaultCryptoService" | ||
val issuer = X500Name("CN=$commonName") | ||
val builder = X509v3CertificateBuilder( | ||
/* issuer = */ issuer, | ||
/* serial = */ serialNumber, | ||
/* notBefore = */ notBeforeDate, | ||
/* notAfter = */ notAfterDate, | ||
/* subject = */ issuer, | ||
/* publicKeyInfo = */ SubjectPublicKeyInfo.getInstance(keys.public.encoded) | ||
) | ||
val signatureAlgorithm = X509SignatureAlgorithm.RS256 | ||
val contentSigner: ContentSigner = signatureAlgorithm.getContentSigner(keys.private) | ||
val certificateHolder = builder.build(contentSigner) | ||
certificateHolder.signature | ||
val bcSig = | ||
(ASN1Sequence.fromByteArray(certificateHolder.encoded) as DLSequence).elementAt(2) | ||
.toASN1Primitive().encoded | ||
CryptoSignature.RSAorHMAC.parseFromJca(certificateHolder.signature).encodeToDer() shouldBe bcSig | ||
CryptoSignature.parseFromJca( | ||
certificateHolder.signature, | ||
SignatureAlgorithm.RSA(Digest.valueOf(digest), RSAPadding.PKCS1) | ||
).encodeToDer() shouldBe bcSig | ||
|
||
} | ||
} | ||
|
||
|
||
}) | ||
|
Oops, something went wrong.