Search code examples
google-chromecryptographyx509tls1.2python-cryptography

What causes Chrome "<domain name> doesn't adhere to security standards."


For local testing of an HTTPS-accessible service, I'm generating my own keys and certificates with the below program. No doubt the certificates constructed by the program don't meet best practices for real world certificates in various ways. However, the particular problem or problems that cause Chrome to reject them with this "doesn't adhere to security standards" error eludes me.

The full (less domain) error reported by Chrome is:

chrome is so sad but I don't know why

The program that generates the certificates, keys, etc is:

#!/usr/bin/env python

from __future__ import unicode_literals, print_function

from string import uppercase
from datetime import datetime, timedelta

from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives.hashes import SHA256
from cryptography.hazmat.primitives import serialization
from cryptography.x509 import (
    CertificateBuilder,
    SubjectAlternativeName,
    BasicConstraints,
    DNSName,
    Name,
    NameAttribute,
)
from cryptography.hazmat.backends import default_backend

def cert(issuer, subject, issuer_key, subject_key, ca):
    builder = CertificateBuilder(
    ).issuer_name(
        Name([NameAttribute(NameOID.COMMON_NAME, issuer)]),
    ).subject_name(
        Name([NameAttribute(NameOID.COMMON_NAME, subject)]),
    ).add_extension(
        SubjectAlternativeName([DNSName(subject)]),
        critical=False,
    )
    if ca:
        builder = builder.add_extension(
            BasicConstraints(True, None),
            critical=True,
        )
    return builder.public_key(subject_key.public_key(),
    ).serial_number(1,
    ).not_valid_before(datetime.utcnow(),
    ).not_valid_after(datetime.utcnow() + timedelta(days=365),
    ).sign(issuer_key, SHA256(), default_backend(),
    )

def main(num_certs, subject_name):
    keys = tuple(
        rsa.generate_private_key(
            public_exponent=65537,
            key_size=1024,
            backend=default_backend(),
        )
        for i in range(num_certs)
    )

    names = list(
        ch + ".invalid"
        for ch
        in uppercase.decode("ascii")[:len(keys) - 1]
    ) + [subject_name]

    certs = tuple(
        cert(
            issuer=issuer_name,
            subject=subject_name,
            issuer_key=issuer_key,
            subject_key=subject_key,
            ca=is_ca,
        )
        for (issuer_name, subject_name, issuer_key, subject_key, is_ca)
        in zip(
            names[:1] + names[:-1],
            names,
            keys[:1] + keys[:-1],
            keys,
            range(len(keys) - 1, -1, -1),
        )
    )

    print("\n".join(
        key.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.TraditionalOpenSSL,
            encryption_algorithm=serialization.NoEncryption(),
        for key
        in keys
    ))

    print("\n".join(
        cert.public_bytes(serialization.Encoding.PEM)
        for cert
        in certs
    ))

main(3, "<some domain name>")

The program spits out the keys and then the certificates. With the default setting of a chain length of 3, there's a CA key/cert, an intermediate key/cert, and a server key/cert.

Here's an example of its output:

-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCx5455hmlbJ/jWgZDuoPy6ymVSHarTOmSMYWp9jTae3Y5t7WEB
8mYdjW/3kZbr8+GVj2gSVHPdQMQdLMwgGmZKnG0VmiZsjHBBu3TA4ZymNGCppUPy
+z4stSEhLA+m0x8yAGt5qorbHcWo9rQnSXTtLD0RlGS4SUutxXaYF88sVwIDAQAB
AoGATvHsPW0x72uLdtTEFcCGpfUOhSP5HAa7e7f244P4iwLSI2HFPHHucorC9t86
U7ZDknSyv/+N8s68uB2a71wHq7JXwRzaU49sQk5NcPHgT5VjYPKtyL+0eY1hXqcn
zzIYRxtFAYiJXPa2ghKHBuP/tpMXMhIkMmMyfYJfd2a9YXECQQDlt7s010CvQcBu
wxa1riZUhp/a5MaaRPMJrJ0H8FFD34i953p0bddyyybSEyNpTfFTF42dfIAgLNDb
YeJj+wLTAkEAxkJA/F5TcXAxdEXtJgXU1zdzEfvrUFNfFR1Vf/Kzkr0618FqQZWL
lLHckqcqH4I+vdw2ycy7kpY0JDkRIBzV7QJAN5+WkAPzILy+GNPaYuGpXFxAxuMQ
h/hcFSKb33k8ZD/zP3CWgSy7t4sjekiyEWSTI7iXTOQBrkjLxeNcyzLTiwJAdHiV
vu0XLkxP8VPnNvA0Et9TbZxGqKDh+gCKqykEz871U60f5Dmbj5ZR06H7ABm/DEDj
uvfYtgwhw6n24puuHQJBAKSAxj+qsjRk8fK9J6GKZ+qaMNEQlzHdQH9LVjzlCSlP
r9GkzmdLnlfVPck3ytJhkgYWQgSE3eh45kGkDOkGZ8U=
-----END RSA PRIVATE KEY-----

-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDZPrkocPoakI93K2Z3pF8rHaq6L84ZG7o0UbWu5zgXc64PhBFU
xALTRbcGTVhIjViJKDue7iYq5/5TfGOXsF3gXxcXt5OQT9JN1t42T1FzuKxVwgg5
vXqjGFHLZJqBNCG6wGuD4R7/wPro7Pt3rVEMSt9tLvb+CF53LbTM0SyJFQIDAQAB
AoGACk8lrjueQsB1bmxK0oakVYF05pz6JMriDTWLb59dVA+TRP05bVJX5/q48r2c
4OSEPQ4BtksK2KJluUR/3WTrL3Ii562zmNYWAZ6BM+aBt/FZDQY01og4kLVnOfU+
NRyhOThogIvXLCiUMNTTixZ7wO7TYa0bJc0tLBr0Guwk5YkCQQD9gG06iV4P7EfI
hHwR6q6tjGs54UVCWras26iKvb9Kob9DWIR510NowUZ5ALVAyWT9mpJvZy4+E6I4
O6lugpfLAkEA22LSm7h+1Ck3kVQYwvKrG9XNSe7rgPYH6mWPogoAZxXO53K74Hih
h8ZG/+JmuQOA5TJf5N1xRAncr6cUjFSGnwJBAM0SzMozAEYPVg7PpnL0EDVTSBb9
twKz0d3KoPEECTD94nU/sYPDccPXvwP6X6a2hZ1nIxk+Njl/tpaZJTrCKLsCQEvf
78sfke26m5dNqIqz9u3XkfqCAT1G2hH9MiHup5j/d+GgUs4dqnAU6TVSjghq58dd
FsFGvQe1CXhOptKp4S0CQQDy5yZ3qmtLhtGfO+c84skkxjcnwHwSR82tbBWaBpqo
tC2UYL7MrXBoNF/bgES+DKF5AdUqHyU6ecU0oq4eVY2f
-----END RSA PRIVATE KEY-----

-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQC4fK/bPNx/M5lu0EL5iwFYB2wy+gpgBrnj77IRoDrtrOyBIiOa
LN+iBzxuINflFX+dFPqLGEc15Kuxe+HyZZDG9XOFt3qZ/0ijoi/x7BB1ZaNxGsF+
Tj4HAvEKKYjUz54cjnhDpt5ZOcJXbAYMNIODBMJJX8Ghg+K7whBQnqFSFQIDAQAB
AoGAIE7NqTI2VxxdMVfNctASEy1xmFfLe1eSNEWkxItv5nGTFWY6H+Td4Q0tWwfr
ZxXlvEeRPMyqo9iA7NsKDZ4VxUW1VBw8Cw4Ua5RDtsRZUL9wc16Wk0y5pwCjWDrP
DI8yRBGmtx+5uY0CNeYQ0mQA1SHC9KtrDRC2kHIDfYN3nh0CQQDmc5/nBV0RTjKs
EdeiRlhAuwEC2zwNQYF/xZzfL9PS65t13Rm1mW2G75RMrjFJclXe+y/SdAibYNJi
lucSsckLAkEAzPCOOvxKjjXTeCyfc1fAYZMOhz/oMy4t+qy2Yc6Lp6DJrhR3T3JC
9qjaLh2a+OnwIPrn5EGQWSLXlSSHNr+FXwJAWWV7HzQ+cSsjjwpw2tts+tdQQhpn
xkCmCrnO6+lyw3xwVx2JDqBRE6o2njRonDRFSXWpjHtEp3m8w1AEnYToFwJAfVFf
98vMn1dkv6ixvCtdtYziJmw6xgkoDpBMWlSd61wT14ImTwt0zTYFbIun9yu+Lbyf
zmEVLpxyrX2PvTeyCwJAP1bQmjTVTMv1ahn9QvarbsqlOV3lMbiyfHREVAGON9LA
e8UCAlL1u0RuV2lqhK8rlkMqxUuZ/D6uDlLrTJpCew==
-----END RSA PRIVATE KEY-----

-----BEGIN CERTIFICATE-----
MIIByjCCATOgAwIBAgIEWVRCgjANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAlB
LmludmFsaWQwHhcNMTcwNjI4MjM1NzU0WhcNMTgwNjI4MjM1NzU0WjAUMRIwEAYD
VQQDDAlBLmludmFsaWQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALHnjnmG
aVsn+NaBkO6g/LrKZVIdqtM6ZIxhan2NNp7djm3tYQHyZh2Nb/eRluvz4ZWPaBJU
c91AxB0szCAaZkqcbRWaJmyMcEG7dMDhnKY0YKmlQ/L7Piy1ISEsD6bTHzIAa3mq
itsdxaj2tCdJdO0sPRGUZLhJS63FdpgXzyxXAgMBAAGjKTAnMBQGA1UdEQQNMAuC
CUEuaW52YWxpZDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4GBADfL
MQitgG+iFEraLMoXzkO65T1JnKIY4rnpW6bJP0Mt2PaSCzvH3AlPnA7ZGvw+x5+b
EdhaxiY3sweSfbRaYubhDHaL8lNB0So4SP1hVFNFQjSLR1aGqoeqY7IYhIzpQ5MK
Pb+sYmvdko45431t8GJOkb9Pg7N/o1aRfzCK2Lca
-----END CERTIFICATE-----

-----BEGIN CERTIFICATE-----
MIIByjCCATOgAwIBAgIEWVRCgjANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAlB
LmludmFsaWQwHhcNMTcwNjI4MjM1NzU0WhcNMTgwNjI4MjM1NzU0WjAUMRIwEAYD
VQQDDAlCLmludmFsaWQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANk+uShw
+hqQj3crZnekXysdqrovzhkbujRRta7nOBdzrg+EEVTEAtNFtwZNWEiNWIkoO57u
Jirn/lN8Y5ewXeBfFxe3k5BP0k3W3jZPUXO4rFXCCDm9eqMYUctkmoE0IbrAa4Ph
Hv/A+ujs+3etUQxK320u9v4IXncttMzRLIkVAgMBAAGjKTAnMBQGA1UdEQQNMAuC
CUIuaW52YWxpZDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4GBADTP
BSezJqx9+7MZVqLcFz0K5K9NsVr5NRn8naC/W8mDNaSet4aeHLWZgVHwMZAiRka8
aAPYwoqXjjjS1/0Z/+eag24D81g2JvSk0t9dB44OCFfq2sgm1ERP0UW5BUKTf2iJ
WyOLpoMVFAeVqp4wug3IcWOOv8JAXmq9oAwlT92g
-----END CERTIFICATE-----

-----BEGIN CERTIFICATE-----
MIIB0TCCATqgAwIBAgIEWVRCgjANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAlC
LmludmFsaWQwHhcNMTcwNjI4MjM1NzU0WhcNMTgwNjI4MjM1NzU0WjAgMR4wHAYD
VQQDDBVzdGFja292ZXJmbG93LmludmFsaWQwgZ8wDQYJKoZIhvcNAQEBBQADgY0A
MIGJAoGBALh8r9s83H8zmW7QQvmLAVgHbDL6CmAGuePvshGgOu2s7IEiI5os36IH
PG4g1+UVf50U+osYRzXkq7F74fJlkMb1c4W3epn/SKOiL/HsEHVlo3EawX5OPgcC
8QopiNTPnhyOeEOm3lk5wldsBgw0g4MEwklfwaGD4rvCEFCeoVIVAgMBAAGjJDAi
MCAGA1UdEQQZMBeCFXN0YWNrb3ZlcmZsb3cuaW52YWxpZDANBgkqhkiG9w0BAQsF
AAOBgQBGj3dezNMMzE4PqkojXkenqKD6NlksldpRL3TOVAXCK6L0NciJbQcxi/9W
zfcaVQBGvNjmg6ieNYCamF+Fz/hg+m4pTrKLy54UnyOa8gUTg+tPJuJHO2FsdeOm
tbgQKLrqpBUJX4+SzEMQYzZfPhOj29SzItCDeRjYhn0m7Otp/Q==
-----END CERTIFICATE-----

Solution

  • All three of those certificates have the exact same serial number (0x59544282). Chrome doesn't like that -- you need to use a unique serial number for each certificate signed by your CA.