How to check, if a private key is a valid Let's Encrypt account key?

FYI, there is a script/working-example in the josepy directory on converting from JWK to PEM:

I only know this because I contributed it a while back :wink:

3 Likes

It can also convert from PEM to JWK it seems! At least, it does have a pem_to_jwk() function, but I'm not sure if that function is directly callable from the CLI.

4 Likes

Yes. That function is just there so it can roundtrip/self-test.

pem_to_jwk is a trivial operation in josepy, because the library has native support for loading pem and dumping json. translating JWK TO PEM was a bit of a hassle, as it took a bit of research to find the right encoding hooks and params to accomplish it. that's why the example exists!

(edit: translating JWK TO PEM is so hard, I originally wrote "PEM TO JWK" and @Osiris had to point that out to me in the next comment.)

3 Likes

You probably mean JWK to PEM here :wink:

3 Likes

FWIW, I recently modified CertSage to store the account private key as its sole saved account information rather than a json file with more as before. This means that it's now trivial to simply put your suspected account key as account.key or account-staging.key into CertSage's data directory. If the suspected key is an actual account key, CertSage will continue as normal. If not, an exception will be thrown. I will be posting the updated version in the near future.

2 Likes

A colleague has proposed another solution, based on the ansible acme_account_info plugin. No need to tinker with true source code, you'll just need a yaml playbook file like this one:

- hosts: localhost
  gather_facts: no
  tasks:
    - name: Check whether an account with the given account key exists
      acme_account_info:
        acme_version: 2
        acme_directory: "{{ acme_directory_url | default('https://acme-v02.api.letsencrypt.org/directory') }}"
        account_key_src: "{{ acme_account_key_src | default('account-private-key.pem') }}"
      register: account_data
    - name: Verify that account exists
      assert:
        that:
          - account_data.exists
    - name: Print account URI
      debug: var=account_data.account_uri
    - name: Print account contacts
      debug: var=account_data.account.contact
    - name: Print account details
      debug: var=account_data

Assuming you have saved that file to ansible-check-account.yaml and want to check file my_suspected_account_key.pem you can invoke it like this:

ansible-playbook ansible-check-account.yaml --extra-vars 'acme_account_key_src=my_suspected_account_key.pem' --extra-vars 'acme_directory_url=https://acme-staging-v02.api.letsencrypt.org/directory'

The above command checks against Let's Encrypt staging. I you want to check against LE prod instead, just omit the acme_directory_url. The playbook defaults to LE prod.

If the account already exists, the above should succeed and print account details, including the account uri (which in turn contains the account id). If the account does not exist or the key is invalid, the above should fail.

Caution: On success the play will print the account private key verbatim! Edit the playbook and remove the bottom-most task if you want to avoid that.

4 Likes

No, it's not the private key. It's the public one. The field is called public_account_key :wink:.

2 Likes

Indeed @dennis-benzinger-sap. Actually, I get two fields: key and public_account_key. But both of them only contain the public part of the key.

I could have sworn that I've seen a private key somewhere in the ansible outputs. But I cannot reproduce that anymore. So probably no need to worry.

Btw, thanks for proposing the ansible solution!

2 Likes

I've upgraded https://github.com/aptise/peter_sslers to support checking a key without registering an account as well. Thank you, @_az

Steps:

  • Upload a PEM or JWK key as "New Acme Account Key"
  • Click the button "Check Against ACME Server"

This only checks one account at a time but PeterSSLers offers a JSON API, so the entire process can be easily automated.

3 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.