quarkus icon indicating copy to clipboard operation
quarkus copied to clipboard

CLI: add support for RSA command

Open FroMage opened this issue 3 years ago • 27 comments

This allows users to create RSA pairs easier than the current openssl usage we document:

$ openssl genrsa -out rsaPrivateKey.pem 2048
$ openssl rsa -pubout -in rsaPrivateKey.pem -out src/main/resources/publicKey.pem
$ openssl pkcs8 -topk8 -nocrypt -inform pem -in rsaPrivateKey.pem -outform pem -out src/main/resources/privateKey.pem

Versus:

$ quarkus rsa
Public and private keys created in /home/stephane/src/java-eclipse/aviouf/src/main/resources/public-key.pem and /home/stephane/src/java-eclipse/aviouf/src/main/resources/private-key.pem
You can use this configuration for JWT:

mp.jwt.verify.publickey.location=public-key.pem
mp.jwt.decrypt.key.location=private-key.pem
smallrye.jwt.sign.key.location=private-key.pem
smallrye.jwt.encrypt.key.location=public-key.pem
 
quarkus.native.resources.includes=public-key.pem
quarkus.native.resources.includes=private-key.pem

FroMage avatar Dec 14 '21 09:12 FroMage

@cescoffier: @ebullient mentionned you're working on SSL stuff that might be related, do you think so?

FroMage avatar Dec 14 '21 09:12 FroMage

It is definitely related, even if my goal is to centralize TLS management in a single extension (instead of having different extensions with separate configurations). It would also allow ACME.

Certs generation was definitely on the list feature I wanted to have. I was a bit puzzled by mTLS with self-cert.

cescoffier avatar Dec 14 '21 09:12 cescoffier

@FroMage Steph, would you like to add a support for EC along the way ? The code for RSA can be reused, the only thing that has to be customized is the EC vs RSA when creating a factory with the 2048 bit skipped in the former case.

sberyozkin avatar Dec 14 '21 12:12 sberyozkin

@sberyozkin -- 2048 or 4096?

ebullient avatar Dec 14 '21 14:12 ebullient

I'm not sure I would like to have this in Quarkus CLI proper. Looks like a source of future security issues if we don't maintain the algorithms very properly.

gsmet avatar Dec 14 '21 22:12 gsmet

Looks like a source of future security issues if we don't maintain the algorithms very properly.

WDYM maintain? Those are exactly the same sort of keys we'd get from openssl, and provided by the JDK. If those are broken, they're horribly broken and require a new JDK anyway, but that's not because we botched it.

FroMage avatar Dec 15 '21 14:12 FroMage

I'm more talking about the best practices in security. Typically, DSA keys are now considered bad practices but they were perfectly acceptable years ago. At some point 2048 might not be considered good enough. Things like that. Basically, I'm talking about us generating at some point keys that are considered weak.

If we include this, we need to make sure it stays up to date with the current security best practices.

@ebullient I'll let you decide the fate of this one, given it's CLI :).

gsmet avatar Jan 12 '22 14:01 gsmet

I can add options for EC/RSA and key size. I wonder what the recommended key size is these days.

FroMage avatar Jan 14 '22 13:01 FroMage

This workflow status is outdated as a new workflow run has been triggered.

:no_entry_sign: This workflow run has been cancelled.

Failing Jobs - Building e091093ca18b6f151f396a2f9b3c5d4025bdcb49

Status Name Step Failures Logs Raw logs
:hourglass: Initial JDK 11 Build :warning: Check → Logs Raw logs
:hourglass: Attach pull request number :warning: Check → Logs Raw logs
:hourglass: CI Sanity Check :warning: Check → Logs Raw logs

quarkus-bot[bot] avatar Jan 14 '22 13:01 quarkus-bot[bot]

Well, if I add support for EC it's not quarkus rsa anymore, is it? So another command quarkus ec? Or quarkus keygen?

FroMage avatar Jan 14 '22 14:01 FroMage

Changed to genkey added EC option and key size options. The defaults are fine according to https://www.keylength.com/en/compare/

Let's call it a day and merge this at some point ;)

FroMage avatar Jan 14 '22 15:01 FroMage

This workflow status is outdated as a new workflow run has been triggered.

Failing Jobs - Building c35812d0b6afed5729dd5e298e1bdb62c9a43e11

Status Name Step Failures Logs Raw logs
Initial JDK 11 Build Build Failures Logs Raw logs

Failures

:gear: Initial JDK 11 Build #

- Failing: devtools/cli 

:package: devtools/cli

Failed to execute goal net.revelc.code.formatter:formatter-maven-plugin:2.17.1:validate (default) on project quarkus-cli: File '/home/runner/work/quarkus/quarkus/devtools/cli/src/main/java/io/quarkus/cli/Genkey.java' has not been previously formatted. Please format file and commit before running validation!

quarkus-bot[bot] avatar Jan 14 '22 15:01 quarkus-bot[bot]

Formatted and rebased

FroMage avatar Jan 18 '22 14:01 FroMage

Failing Jobs - Building 51d1e960f6a0269f02e36e5eb88588bb696f14ef

Status Name Step Failures Logs Raw logs
:heavy_check_mark: JVM Tests - JDK 11
JVM Tests - JDK 17 Build Failures Logs Raw logs

Full information is available in the Build summary check run.

Failures

:gear: JVM Tests - JDK 17 #

- Failing: devtools/cli 

:package: devtools/cli

io.quarkus.cli.CliGenkeyTest.testCommandRsa line 83 - More details - Source on GitHub

org.opentest4j.AssertionFailedError: Key size is not valid: 256 (expected 512) ==> expected: <true> but was: <false>
	at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55)
	at org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:40)

quarkus-bot[bot] avatar Jan 18 '22 14:01 quarkus-bot[bot]

@FroMage CI is not happy

@ebullient I let you have a look at this one.

gsmet avatar Jan 18 '22 17:01 gsmet

Huh, test fails with a generated key size of 256 when it should be 512. That's quite a margin of error. Damn.

FroMage avatar Jan 19 '22 14:01 FroMage

hmm. Did we ever decide what we wanted to do here?

ebullient avatar Aug 04 '22 19:08 ebullient

Is this still relevant after the TLS work and quarkus tls CLI tool support @cescoffier @FroMage ?

rsvoboda avatar Aug 26 '24 19:08 rsvoboda

Well, the original issue was about JWT, not TLS. The tls command can generate certificates, but I'm not sure they can be used for that use case (anybody knows what attributes/permissions are required for this use case?).

cescoffier avatar Aug 27 '24 06:08 cescoffier

The original issue was about creating private/public keys, used by JWT, but I got stuck because my code did not appear to pass the tests on Windows. If tls can create private/public keys suitable for JWT that'd be great. Can it?

FroMage avatar Aug 27 '24 10:08 FroMage

@FroMage good question. What's the requirement? Maybe @sberyozkin knows?

cescoffier avatar Aug 27 '24 12:08 cescoffier

What's the requirement?

Well, not sure what you ask, really. The original description sums is up pretty correctly:

https://github.com/quarkusio/quarkus/pull/22182#issue-1079526928

I want to make it trivial for users to generate private/public keys so that JWT can use them

FroMage avatar Aug 27 '24 13:08 FroMage

Ok, so the TLS commands won't work for you. It generates certificates. You could extract the public and private keys, but a certificate has more metadata which are irrelevant for JWT.

cescoffier avatar Aug 27 '24 14:08 cescoffier

Maybe a bit more explanation. The TLS command can generate PEM certificates which consists of a private key (all good for JWT) but also a certificate file:

-----BEGIN CERTIFICATE-----
MIIDSTCCAjGgAwIBAgIHAJfI0c6BUTANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMjQwODIwMDgwMDE3WhcNMjUwNjE4MDgwMDE3WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGnd3J4sSTrNEGThkp7TmAh+g39bCU+jI3G5gDX4GDPYrVUdK2/MoY/j9UTIPZbiGgPh/7Wq8ZkOeatFHgEE5259WXQJzZghvvnJi/ajX8STDH2+LV0byDkMCtRgvQoXB4ACx9LFZiMJ315HxfFfs3NOwXi7yQTJbNewm4LynGyYLk0nIJH1hxdQM6hUiNI0uqT/8mzCT9CO8AihZn0b3dhxg0e1D3DNAivihpfKAwF0F6v4ZE0xh816ao6C+pJzMvIRR1Q41hMWZy5Oqh1MtHpg4q2cC3Ew7OYK6R//L5pVOb1FKG4vYT++W7sUg8ny8UpSgHLjbbegX6aAClbuExAgMBAAGjgZ8wgZwwHQYDVR0OBBYEFFwnAADkRURzRlSbjy03w32frWgoMB8GA1UdIwQYMBaAFFwnAADkRURzRlSbjy03w32frWgoMA4GA1UdDwEB/wQEAwID+DAJBgNVHRMEAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAgBgNVHREEGTAXgglsb2NhbGhvc3SHBH8AAAGHBAAAAAAwDQYJKoZIhvcNAQELBQADggEBAJ8eSPVS310qSRNraaXxZEl92ksZuBQC5ZTaev1xaoZaYJc+LmEJVeJtE1Yra8YJQxJ2mfnKpd+aMYTLupj1jucaXz2KoYJ2aKQJb7UA6x9h1kNRkODIWVlrkVoXYE4Jrfx0wv88DqlCqcTFke+BfKxzD07i7nOjFqLkeRSUMKdG90yCZXJlVUOZw3gxqmoM9EyM/+24cghhvj4iKto+Dnb2Nm0JPkbKImz4bYklc6hbpeegV+TVwPv/pV766wUXsG9JO1l/0WyhBxTNtUuhKzQy3/K9ggPj7DnKI7WTGOlpOjlCgHLqXYShTWLZPLc3nP8txW4VWwoa0z7N501LB9A=
-----END CERTIFICATE-----

This contains a public key and additional metadata. I don't believe (please correct me if I'm wrong) that JWT can ingest that directly. It probably (again, just a guess) needs a public key - something like:

-----BEGIN RSA PUBLIC KEY-----
MIIBigKCAYEAq3DnhgYgLVJknvDA3clATozPtjI7yauqD4/ZuqgZn4KzzzkQ4BzJ
ar4jRygpzbghlFn0Luk1mdVKzPUgYj0VkbRlHyYfcahbgOHixOOnXkKXrtZW7yWG
jXPqy/ZJ/+...
-----END RSA PUBLIC KEY-----

My certificate generator provides the method to generate these files, but the TLS commands do not have a way to generate them, write them on disk, and configure the application.

cescoffier avatar Aug 28 '24 06:08 cescoffier

OK, indeed, plus they must be in two different files, I'm pretty sure.

So, if you got TLS to generate valid public/private keys, I'm very interested in how you're testing that you're generating valid certificates in a way which works on Windows?

I'm using https://github.com/quarkusio/quarkus/pull/22182/files#diff-cc26500c07df78f060f6cec25a52d12a1e233aa7c6561e176470d6da040eea5aR86 to test that the parameters of the key are valid, but on Windows they don't match the parameters I set when creating them.

FroMage avatar Aug 28 '24 08:08 FroMage

In my case, I use http servers and clients to verify the certificates (so not something you can do)

Looking at your code, I believe I used a different way to write my pem files. Let me check.

cescoffier avatar Aug 28 '24 11:08 cescoffier

Nope, I'm using something very similar:

public static void writePrivateKeyToPem(PrivateKey privateKey, File output) throws Exception {
        try (FileWriter fileWriter = new FileWriter(output);
                BufferedWriter pemWriter = new BufferedWriter(fileWriter)) {
            pemWriter.write("-----BEGIN PRIVATE KEY-----\n");
            pemWriter.write(Base64.getEncoder().encodeToString(privateKey.getEncoded()));
            pemWriter.write("\n-----END PRIVATE KEY-----\n\n");
        }
    }

cescoffier avatar Aug 28 '24 11:08 cescoffier

So probably you don't test the certificates as I do. As long as they work… But that's the thing, I can't figure out if they have the proper required bits. I know they work, but I can't be sure they have the parameters that I asked them to have :(

FroMage avatar Sep 05 '24 09:09 FroMage