Unable to Renew Certs - ValueError: not enough values to unpack (expected 3, got 2) - split_certs(fullchain_pem)

Hi everyone,

I'm encountering an issue with renewing the Let's Encrypt certificate for our domain

app-auth.dentsu-msl.com'

our domain is set to expire by March 14th, 2024

We presently use a Python script that helps with our certs renewal and splitting of certs for certain
Applications.
Below is a code snippet that handles this process. We used this last year for the renewal process and it worked fine as expected.


acm_cert_data_cache = {}
def acm_certificate_data_for_region(aws_region):
    if acm_cert_data_cache.get(aws_region):
        return acm_cert_data_cache[aws_region]
    else:
        data = get_acm_certificate_data(aws_region)
        acm_cert_data_cache[aws_region] = data
        return data


def split_certs(fullchain_pem):
    certs = []
    lines = fullchain_pem.split("\n")
    cert = []
    for line in lines:
        if line.strip():
            cert.append(line)
        if 'END CERTIFICATE' in line:
            certs.append('\n'.join(cert).strip() + '\n')
            cert = []
    return certs


def join_certs(certs: list):
    return '\n'.join(certs)


def create_certs_for_domain(domain, challenge_type, cert_type, cert_dir,
        sans, upload=True, is_split_cert=False):
    '''Returns tuple of PEM and private key.'''
    cert_private_key = generate_key()
    include_qa = ((challenge_type == DNS_CHALLENGE_TYPE) and
            (cert_type != 'internal'))
    cert_signing_request = generate_signing_request(domain,
        cert_private_key, cert_type, sans, include_qa)

    fullchain_pem, private_key_pem = create_certs(domain=domain,
        challenge_type=challenge_type,
        cert_private_key=cert_private_key,
        cert_signing_request=cert_signing_request)

    cert_set_count = 2

    if is_split_cert:
        server, intermediate, root = split_certs(fullchain_pem)
        trust_pem =  join_certs([private_key_pem, fullchain_pem])
        cert_set_count = 6

    # consumers can use this metadata to confirm that the set is complete
    expiry = (datetime.datetime.now() + datetime.timedelta(90)).isoformat()
    metadata = { "cert-set-id": str(uuid.uuid4()),
        "cert-set-count": str(cert_set_count), "cert-expiry-iso": expiry }
    if upload:
        if is_split_cert:
            put_s3_object(path='{}/certificates/{}-server.crt'.format(cert_dir, domain),
                text=server, metadata=metadata.copy())
            put_s3_object(path='{}/certificates/{}-intermediate.crt'.format(cert_dir, domain),
                text=intermediate, metadata=metadata.copy())
            put_s3_object(path='{}/certificates/{}-root.crt'.format(cert_dir, domain),
                text=root, metadata=metadata.copy())
            put_s3_object(path='{}/certificates/{}-trust.crt'.format(cert_dir, domain),
                text=trust_pem, metadata=metadata.copy())

        put_s3_object(path='{}/certificates/{}.crt'.format(cert_dir, domain),
            text=fullchain_pem, metadata=metadata.copy())
        put_s3_object(path='{}/keys/{}.key'.format(cert_dir, domain),
            text=private_key_pem, metadata=metadata.copy())

    return (fullchain_pem, private_key_pem)


This year we are running into issues with the below output

ValueError: not enough values to unpack (expected 3, got 2)
split_certs(fullchain_pem) -

"Error processing domain 'app-auth.dentsu-msl.com'","params":[]},"logger":"__main__","metadata":{"display_title_with_tree_label":false,"filename":"renewer.py","function":"create_certs_for_domain","in_app_frame_mix":"system-only","type":"ValueError","value":"not enough values to unpack (expected 3, got 2)"},"modules":{"acme":"0.34.2","boto3":"1.28.31","botocore":"1.31.36","certifi":"2021.10.8","certificate-automation":"4.1.0","cffi":"1.15.0","chardet":"3.0.4","cryptography":"35.0.0","docutils":"0.15.2","idna":"2.8","jmespath":"0.10.0","josepy":"1.10.0","mock":"4.0.3","pem":"20.1.0","pip":"20.1.1","pycparser":"2.20","pyopenssl":"21.0.0","pyrfc3339":"1.1","python-dateutil":"2.8.0","pytz":"2021.3","pyyaml":"5.4","requests":"2.22.0","requests-toolbelt":"0.9.1","s3transfer":"0.6.2","sentry-sdk":"0.20.3","setuptools":"47.1.0","six":"1.16.0","urllib3":"1.25.11"},"nodestore_insert":1708876900.656062,"received":1708876894.590229,"sdk":{"name":"sentry.python","version":"0.20.3","integrations":["argv","atexit","boto3","dedupe","excepthook","logging","modules","stdlib","threading"],"packages":[{"name":"pypi:sentry-sdk","version":"0.20.3"}]},"timestamp":1708876893.5853,"title":"ValueError: not enough values to unpack (expected 3, got 2)","type":"error","version":"7"}

I'm reaching out to the community for any insights or suggestions on how to resolve this issue and successfully renew our certs.
Is it okay that the Certs have just two certs instead of 3 ? Is there anything i should be aware of regarding the certificate chain?

Hosting provider - AWS,

Also, we are getting errors ---

There were too many requests of a given type ::

Error: urn:ietf:params:acme:error:rateLimited :: There were too many requests of a given type :: Error creating new order :: too many certificates (5) already issued for this exact set of domains in the last 168 hours: app-auth.dentsu-msl.com,ause2-app-auth.dentsu-msl.com,ausw2-app-auth.dentsu-msl.com,qa-app-auth.dentsu-msl.com, retry after 2024-02-27T00:37:31Z: see https://letsencrypt.org/docs/duplicate-certificate-limit/

...
  File "acme/client.py", line 655, in new_order
    response = self._post(self.directory['newOrder'], order)
  File "acme/client.py", line 95, in _post
    return self.net.post(*args, **kwargs)
  File "acme/client.py", line 1179, in post
    return self._post_once(*args, **kwargs)
  File "acme/client.py", line 1193, in _post_once
    response = self._check_response(response, content_type=content_type)
  File "acme/client.py", line 1048, in _check_response
    raise messages.Error.from_json(jobj)

Thank you

You should not hardcode the amount of certs in the chain.

That's to be expected if you keep on requesting and issuing new certificates on the production environment when there is a problem with your ACME client. The rate limits are exactly for this reason, to keep broken ACME clients from issuing way too much certificates in to short a time.

My advice: go back to the drawing board. Learn more about ACME. Learn more about how to write an ACME client correctly. And try again or fix your current code.

2 Likes

See

3 Likes
3 Likes

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