fjordtools / Errors / self-signed certificate

self-signed certificate

A self-signed certificate was signed with its own key, not by a certificate authority, so nothing the client already trusts vouches for it. The client refuses it, and Node calls it DEPTH_ZERO_SELF_SIGNED_CERT. Development servers and appliances often send one. The fix is to trust that exact certificate, or to use a CA's, not to switch checking off.

Fjordtools team · Seen in OpenSSL, curl, Node and Python · Published · 2 min read

How the tools word it

Node 26 tlsDEPTH_ZERO_SELF_SIGNED_CERT: self-signed certificate; if the root CA is installed locally, try running Node.js with --use-system-ca
OpenSSL 3.6 s_clientverify error:num=18:self-signed certificate
OpenSSL 3.6 verifyerror 18 at 0 depth lookup: self-signed certificate
curl 8.23curl: (60) SSL certificate OpenSSL verify result: self-signed certificate (18)
Python 3.14 sslssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate (_ssl.c:1082)

Common causes

  1. The server uses a certificate it made for itself

    Issuer and subject are the same name, and no other certificate comes with it. The Certificate Decoder says Same as the subject and Self-signed. A development server, a router or an appliance does this out of the box.

    Input

    -----BEGIN CERTIFICATE-----
    MIIBhDCCASmgAwIBAgIBBjAKBggqhkjOPQQDAjAWMRQwEgYDVQQDDAtzZXJ2ZXIu
    dGVzdDAeFw0yNjAxMDEwMDAwMDBaFw0zNjAxMDEwMDAwMDBaMBYxFDASBgNVBAMM
    C3NlcnZlci50ZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5AQZINGTVGz2
    E4ip0sTj/Q9uZjvCjo8aBDmw2fAZGPEnFKRN8E1iv4qf5LuNdsavJmMZ62Ky4XY9
    xCKZleexTaNoMGYwHQYDVR0OBBYEFAcRP2dk59U5vcQBSxUqur3W1NImMB8GA1Ud
    IwQYMBaAFAcRP2dk59U5vcQBSxUqur3W1NImMAwGA1UdEwEB/wQCMAAwFgYDVR0R
    BA8wDYILc2VydmVyLnRlc3QwCgYIKoZIzj0EAwIDSQAwRgIhAKsK71tbzp8UA4fs
    VaX3xgi2yYNRRo211NJ6TpSuV2qMAiEA16zHBGn60FM11g6YiRwqXdsVL5oW6Tf+
    3Z5agmDeGNM=
    -----END CERTIFICATE-----

    Certificate Decoder says

    Issuer · Same as the subject · Self-signed
  2. A self-signed root is normal at the top of a chain

    Every chain ends in a root that signed itself, and the Decoder says the same for it. That is not the problem; trust is. A server certificate is the odd one out: no root ever vouches for it. If the self-signed certificate sits above a server certificate, the wording is self-signed certificate in certificate chain.

    Input

    -----BEGIN CERTIFICATE-----
    MIIBwzCCAWqgAwIBAgIBATAKBggqhkjOPQQDAjA5MRgwFgYDVQQKDA9mam9yZHRv
    b2xzIHRlc3QxHTAbBgNVBAMMFGZqb3JkdG9vbHMgdGVzdCByb290MB4XDTI2MDEw
    MTAwMDAwMFoXDTM2MDEwMTAwMDAwMFowOTEYMBYGA1UECgwPZmpvcmR0b29scyB0
    ZXN0MR0wGwYDVQQDDBRmam9yZHRvb2xzIHRlc3Qgcm9vdDBZMBMGByqGSM49AgEG
    CCqGSM49AwEHA0IABH0DdyM4j2Qm5yUYrP9opJIyAW5oKmYs1KlgD5QaEspetzDt
    LmYCaEdSk051mmCgtov0ROqWiElrHplTLeJ0vQWjYzBhMB8GA1UdIwQYMBaAFLcg
    9Ms28bssX2hEC2iuZ/lj9P4oMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD
    AgEGMB0GA1UdDgQWBBS3IPTLNvG7LF9oRAtormf5Y/T+KDAKBggqhkjOPQQDAgNH
    ADBEAiBJvWgbvsYiq9JtmZfKyepnmBnyzFQ93G+Tu9MHiZSt9wIgLz6fgDWJkUSD
    djhBBe3H4vsZwwTf+tNiFatZWY+Bkno=
    -----END CERTIFICATE-----

    Certificate Decoder says

    Issuer · Same as the subject · Self-signed
  3. A device in the path replaced the certificate

    A firewall, a login page or an appliance that intercepts a connection to a public site can answer with a certificate of its own. If a public site gives this error on one network only, suspect that, and compare with another network.

How to fix it

  1. If you control the server, use a certificate from a CA: a free ACME certificate for a public name, or one from your own CA for an internal name.
  2. To trust one specific certificate, give the client that file: curl --cacert cert.pem, NODE_EXTRA_CA_CERTS=cert.pem for Node, SSL_CERT_FILE=cert.pem for Python and OpenSSL, or openssl s_client -CAfile cert.pem.
  3. To make a development certificate with its name inside, run openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -keyout key.pem -out cert.pem -days 30 -subj "/CN=server.test" -addext subjectAltName=DNS:server.test, then trust cert.pem as above. Without the subjectAltName a browser refuses the name.
  4. Do not switch checking off. curl -k and NODE_TLS_REJECT_UNAUTHORIZED=0 accept any certificate from anyone, for every site the process contacts, and Node prints a warning saying so.
  5. Paste the certificate in the Certificate Decoder: Same as the subject and Self-signed confirm the cause.

Related errors

More error explainers are coming

See all errors.