Needless fact about RSA private key sizes

In case anyone has such a need/desire…

LetsEncrypt will sign RSA certs from 2048-4096 bits.

You are not limited to choosing from only one or the other [2048 | 4096].

You can* choose from [2048 | 2049 | 2050 | 2051 | 2052 | … | 4092 | 4093 | 4094 | 4095 | 4096]

Note: can implies required manual intervention.

2400 = [2^5*3*5^2]	< equally complex ?
3360 = [2^5*3*5*7]	< complicated ?
3456 / 8 = 432^1	< cute ?
3456 = [2^4*3^3*4^2]/2	< halfway balanced ?
3456 = [1^4]*[2^3]*[3^2]*[4^1] * [1^3]*[2^2]*[3^1] < how bizarre !

Certbot defaults to 2048, but accepts any number with --rsa-key-size. It doesn’t even have this dichotomous choice you are referring to.

retracted and restated

@osiris, It seems mileage may vary: (for most) Distro determine which certbot version they run and that version determines which key lengths are permitted.

Test result from certbot version 0.27.0 | OpenSSL 1.1.1 11 Sep 2018
certbot certonly --standalone -d no.ne --rsa-key-size 2050
produced this error:
An unexpected error occurred:
key length wasn’t a multiple of 8: 2050

Test result from certbot 0.31.0 | OpenSSL 1.1.1 11 Sep 2018
Produced private key file with:
RSA Private-Key: (2050 bit, 2 primes)

[completely re-edited]

1 Like

As far as I can see (https://github.com/certbot/certbot/blob/master/certbot/crypto_util.py), certbot itself doesn’t enforce such a multiple of 8 limit.

It did fail in version 0.27.0:
[direct from screen]

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server at
https://acme-v02.api.letsencrypt.org/directory
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(A)gree/(C)ancel: A
An unexpected error occurred:
key length wasn't a multiple of 8: 2050
Please see the logfiles in /var/log/letsencrypt for more details.

[direct from log file]

2019-11-05 12:01:03,345:DEBUG:acme.client:Sending GET request to https://acme-v02.api.letsencrypt.org/directory.
2019-11-05 12:01:03,350:DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
2019-11-05 12:01:03,751:DEBUG:urllib3.connectionpool:https://acme-v02.api.letsencrypt.org:443 "GET /directory HTTP/1.1" 200 658
2019-11-05 12:01:03,752:DEBUG:acme.client:Received response:
HTTP 200
Server: nginx
Date: Tue, 05 Nov 2019 12:01:03 GMT
Content-Type: application/json
Content-Length: 658
Connection: keep-alive
Cache-Control: public, max-age=0, no-cache
X-Frame-Options: DENY
Strict-Transport-Security: max-age=604800

{
  "RlF3uOkqtk8": "https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417",
  "keyChange": "https://acme-v02.api.letsencrypt.org/acme/key-change",
  "meta": {
    "caaIdentities": [
      "letsencrypt.org"
    ],
    "termsOfService": "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf",
    "website": "https://letsencrypt.org"
  },
  "newAccount": "https://acme-v02.api.letsencrypt.org/acme/new-acct",
  "newNonce": "https://acme-v02.api.letsencrypt.org/acme/new-nonce",
  "newOrder": "https://acme-v02.api.letsencrypt.org/acme/new-order",
  "revokeCert": "https://acme-v02.api.letsencrypt.org/acme/revoke-cert"
}
2019-11-05 12:01:09,252:DEBUG:acme.client:Requesting fresh nonce
2019-11-05 12:01:09,252:DEBUG:acme.client:Sending HEAD request to https://acme-v02.api.letsencrypt.org/acme/new-nonce.
2019-11-05 12:01:09,519:DEBUG:urllib3.connectionpool:https://acme-v02.api.letsencrypt.org:443 "HEAD /acme/new-nonce HTTP/1.1" 200 0
2019-11-05 12:01:09,520:DEBUG:acme.client:Received response:
HTTP 200
Server: nginx
Date: Tue, 05 Nov 2019 12:01:09 GMT
Connection: keep-alive
Cache-Control: public, max-age=0, no-cache
Link: <https://acme-v02.api.letsencrypt.org/directory>;rel="index"
Replay-Nonce: 0001gzNY9AhK_EmOg1fi9qgoUE83PmYUIxAnPFFRjRyBct8
X-Frame-Options: DENY
Strict-Transport-Security: max-age=604800


2019-11-05 12:01:09,520:DEBUG:acme.client:Storing nonce: 0001gzNY9AhK_EmOg1fi9qgoUE83PmYUIxAnPFFRjRyBct8
2019-11-05 12:01:09,521:DEBUG:acme.client:JWS payload:
b'{\n  "contact": [\n    "mailto:none@no.ne"\n  ],\n  "termsOfServiceAgreed": true,\n  "resource": "new-reg"\n}'
2019-11-05 12:01:09,531:DEBUG:acme.client:Sending POST request to https://acme-v02.api.letsencrypt.org/acme/new-acct:
{
  "protected": "eyJhbGciOiAiUlMyNTYiLCAiandrIjogeyJuIjogIkFxMlF3d3pwTHdYS0hkQndtalJUdjBhZzJrOXctYm9sSXdHdjVYY2dIWFhwTEdYM0V1eHFneTV3QlNGSFl
mYUJkWmNIdlp1b0pfbnVDMkRPS3ZLZGgzZVpoM1dWQ3EtbUtpVXAtQ0xJZlhVcEd4Y0lRTU15WW5qQm8zVHRRaEhNMGxPVUpPWTVIOVlfQ0NvRm5oTWdTc0NaX2EwZmxHTDhsNC1OU3
Y0WGdMbXlpVngzelR5VlotUWtTMmR5RUN4UkIzNi1jdkpDNWJ3SWpNM1VrSkFFU1dSZjZOREdJZTROM2YxcEt3bHhBYTVMVng4WTZnUjBOX3ozcUprdzM4VHkzODdyNmRkcE5ja1ExM
DBHNUlXUkNQTlA5dmpXVDRFQlkzYVN6X3VRZ25ST1RuSjBXRzNBMmI4dEFKWjZBUVNQU1FnTUMtZ0dvUndOMTJ2cDRfRlpsWWsiLCAiZSI6ICJBUUFCIiwgImt0eSI6ICJSU0EifSwg
Im5vbmNlIjogIjAwMDFnek5ZOUFoS19FbU9nMWZpOXFnb1VFODNQbVlVSXhBblBGRlJqUnlCY3Q4IiwgInVybCI6ICJodHRwczovL2FjbWUtdjAyLmFwaS5sZXRzZW5jcnlwdC5vcmc
vYWNtZS9uZXctYWNjdCJ9",
  "signature": "ASf0d-X4V9wlc1LEAah89Jpjwq8b7ftUtxxQaxCE6hDtCnX4eGK3wPrc335h3VpplUX4Cw6jW500tf_w93qhj2KF3trzrIQP7jNgECg41vUceJA4Mb3zSnlXQHz
Q2oxbF_hBlJIXnsfOxApYWjesKXwq6e6za5iXpXkEGdaPeW9o2IK2z5xIDDifZN78u42Vq6ViuQOe6OA39x4Zt3o8p6V_fY5CSr5eHabgclX742i4_4BhYG7NTuV9LhYU9aFoM02oo4
bXgS0lgdhvQFRuag-zwXGpg1jlUmkIzB1SpFfycEq0SecGp3LiTbYS0S4DqcSPOKYf3J3e90t0YDpD3nY",
  "payload": "ewogICJjb250YWN0IjogWwogICAgIm1haWx0bzpub25lQG5vLm5lIgogIF0sCiAgInRlcm1zT2ZTZXJ2aWNlQWdyZWVkIjogdHJ1ZSwKICAicmVzb3VyY2UiOiAib
mV3LXJlZyIKfQ"
}
2019-11-05 12:01:09,673:DEBUG:urllib3.connectionpool:https://acme-v02.api.letsencrypt.org:443 "POST /acme/new-acct HTTP/1.1" 400 127
2019-11-05 12:01:09,674:DEBUG:acme.client:Received response:
HTTP 400
Server: nginx
Date: Tue, 05 Nov 2019 12:01:09 GMT
Content-Type: application/problem+json
Content-Length: 127
Connection: keep-alive
Cache-Control: public, max-age=0, no-cache
Link: <https://acme-v02.api.letsencrypt.org/directory>;rel="index"
Replay-Nonce: 0002z64Fm-b9UQ4cBAqdiJZbcIaA_y8WsBurC7jSyZ65USE

{
  "type": "urn:ietf:params:acme:error:badPublicKey",
  "detail": "key length wasn't a multiple of 8: 2050",
  "status": 400
}
2019-11-05 12:01:09,674:DEBUG:certbot.log:Exiting abnormally:
Traceback (most recent call last):
  File "/usr/bin/certbot", line 11, in <module>
    load_entry_point('certbot==0.27.0', 'console_scripts', 'certbot')()
  File "/usr/lib/python3/dist-packages/certbot/main.py", line 1364, in main
    return config.func(config, plugins)
  File "/usr/lib/python3/dist-packages/certbot/main.py", line 1238, in certonly
    le_client = _init_le_client(config, auth, installer)
  File "/usr/lib/python3/dist-packages/certbot/main.py", line 641, in _init_le_client
    acc, acme = _determine_account(config)
  File "/usr/lib/python3/dist-packages/certbot/main.py", line 520, in _determine_account
    config, account_storage, tos_cb=_tos_cb)
  File "/usr/lib/python3/dist-packages/certbot/client.py", line 182, in register
    regr = perform_registration(acme, config, tos_cb)
  File "/usr/lib/python3/dist-packages/certbot/client.py", line 207, in perform_registration
    tos_cb)
  File "/usr/lib/python3/dist-packages/acme/client.py", line 863, in new_account_and_tos
    return self.client.new_account(regr)
  File "/usr/lib/python3/dist-packages/acme/client.py", line 606, in new_account
    response = self._post(self.directory['newAccount'], new_account)
  File "/usr/lib/python3/dist-packages/acme/client.py", line 96, in _post
    return self.net.post(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/acme/client.py", line 1204, in post
    return self._post_once(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/acme/client.py", line 1218, in _post_once
    response = self._check_response(response, content_type=content_type)
  File "/usr/lib/python3/dist-packages/acme/client.py", line 1073, in _check_response
    raise messages.Error.from_json(jobj)
acme.messages.Error: urn:ietf:params:acme:error:badPublicKey :: key length wasn't a multiple of 8: 2050
2019-11-05 12:01:09,677:ERROR:certbot.log:An unexpected error occurred:
2019-11-05 12:01:09,677:ERROR:certbot.log:key length wasn't a multiple of 8: 2050

Perhaps:

/usr/lib/python3/dist-packages/cryptography/hazmat/primitives/keywrap.py:        raise ValueError("The wrapped key must be a multiple of 8 bytes")
/usr/lib/python3/dist-packages/cryptography/hazmat/primitives/padding.py:        raise ValueError("block_size must be a multiple of 8.")

does browsers accept those weird sized keys?

I wouldn’t say weird…
“Unusual”

But YES they are accepted.

Another random data point. The Windows crypto libraries I’ve dealt with all seem to support any size (with varying min/max) as long as it’s a multiple of 8. So 2048, 2056, 2064, 2072, etc.

1 Like