1

I'm struggling to make my way through implementing a DTLS 1.2 handshake using ECDSA, and I'm having trouble with the client certificate. When I generate it, it seems as though the subjectPublicKeyInfo is incorrect: in wireshark instead of seeing ECParameters: namedCurve inside the algorithm, I seem to get an unparsed OID.

What I expect: What I expect What I see: What I see

I'm generating the certificate like so (I expect this is full of errors, I'd love any guidance there!):

Generating the keypair:

private fun generateEcKeyPair(): AsymmetricCipherKeyPair {
    val generator = ECKeyPairGenerator()

    val curveSpec = ECNamedCurveTable.getParameterSpec("secp256r1")
    generator.init(
    ECKeyGenerationParameters(
        ECDomainParameters(
            curveSpec.curve,
            curveSpec.g,
            curveSpec.n,
            curveSpec.h,
            curveSpec.seed
            ),
            SecureRandom()
        )
    )
    return generator.generateKeyPair()
}

Generating the certificate (which uses the keypair generated from the above method):

private fun generateX509Certificate(
    subject: X500Name,
    keyPair: AsymmetricCipherKeyPair
): org.bouncycastle.asn1.x509.Certificate {
    val now = System.currentTimeMillis()
    val notBefore = Date(now - Duration.ofDays(1).toMillis())
    val notAfter = Date(now + Duration.ofDays(7).toMillis())

    val certBuilder = X509v3CertificateBuilder(
        subject,
        BigInteger.valueOf(now),
        notBefore,
        notAfter,
        subject,
        SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(keyPair.public)
    )
    val signatureAlgoIdentifier =
        DefaultSignatureAlgorithmIdentifierFinder().find(signatureAlgo)
    val digestAlgoIdentifier =
        DefaultDigestAlgorithmIdentifierFinder().find(signatureAlgoIdentifier)
    val signer =
        BcECContentSignerBuilder(signatureAlgoIdentifier, digestAlgoIdentifier).build(keyPair.private)

    return certBuilder.build(signer).toASN1Structure()
}

What am I doing wrong here? Am I roughly on the right track?

chiragzq
  • 388
  • 1
  • 14
bbaldino
  • 394
  • 3
  • 15

1 Answers1

1

I think I managed to stumble onto the fix for this. I changed my generateEcKeyPair implementation to the following (after adding BouncyCastleProvider as a provider):

fun generateEcKeyPair(): KeyPair {
    val keyGen = KeyPairGenerator.getInstance("EC", "BC")
    val ecCurveSpec = ECNamedCurveTable.getParameterSpec("secp256r1")

    keyGen.initialize(ecCurveSpec)

    return keyGen.generateKeyPair()
}

And it looks like I'm getting the curve named properly in the cert now.

Maybe I was passing the parameters in incorrectly before? Or creating it manually didn't preserve the named curve correctly?

bbaldino
  • 394
  • 3
  • 15
  • The non-provider code was losing the name in converting to ECDomainParameters. There is the ECNamedDomainParameters subclass that can preserve the curve name. It is carried through the key generation into the keys, and would be picked up by SubjectPublicKeyInfoFactory (and PrivateKeyInfoFactory) resulting in a "namedCurve" encoding instead of explicit curve parameters. – Peter Dettman Apr 17 '19 at 08:02