Wildcard SSL Certificates: Solving the *.domain.com vs domain.com Coverage Gap


2 views

When working with wildcard SSL certificates, a common pitfall catches many developers off guard: while *.domain.com covers all subdomains like api.domain.com and blog.domain.com, it explicitly does not include the root domain domain.com. This creates security warnings and connection issues when users access your base domain.

The technical specification (RFC 2818) treats wildcard certificates differently from regular certificates. The asterisk only replaces one subdomain level, and certificate authorities explicitly exclude root domains from wildcard coverage for security reasons.

Here's what Chrome shows when you only have a wildcard cert:

SSL_ERROR_BAD_CERT_DOMAIN
Subject Alternative Name does not include domain.com

Option 1: SAN (Subject Alternative Name) Certificate

Request a certificate with both entries:

openssl req -new -key domain.key -out domain.csr \
    -subj "/CN=*.domain.com" \
    -reqexts SAN \
    -config <(cat /etc/ssl/openssl.cnf \
        <(printf "[SAN]\nsubjectAltName=DNS:domain.com,DNS:*.domain.com"))

Option 2: Multi-Domain Wildcard Certificate

Some CAs offer certificates covering:

*.domain.com
domain.com
*.sub.domain.com
sub.domain.com

Example from Let's Encrypt using certbot:

certbot certonly --manual --preferred-challenges=dns \
    -d domain.com -d *.domain.com

Option 3: Separate Certificates

For high-security environments, maintain separate certificates:

# Nginx configuration example
server {
    listen 443 ssl;
    server_name domain.com;
    ssl_certificate /path/to/root_cert.pem;
    ssl_certificate_key /path/to/root_key.pem;
    # ... other config
}

server {
    listen 443 ssl;
    server_name *.domain.com;
    ssl_certificate /path/to/wildcard_cert.pem;
    ssl_certificate_key /path/to/wildcard_key.pem;
    # ... other config
}

Testing across browsers reveals different behaviors:

  • Chrome 85+: Strict SAN checking
  • Firefox 80+: Follows RFC strictly
  • Safari 14: Partial wildcard support

For Let's Encrypt users, this bash script automates renewal:

#!/bin/bash
DOMAIN="domain.com"
EMAIL="admin@domain.com"

certbot certonly --dns-route53 -d "$DOMAIN" -d "*.$DOMAIN" \
    --non-interactive --agree-tos --email "$EMAIL" \
    --preferred-challenges dns-01

# Combine certificates for HAProxy
cat /etc/letsencrypt/live/$DOMAIN/fullchain.pem \
    /etc/letsencrypt/live/$DOMAIN/privkey.pem \
    > /etc/haproxy/certs/$DOMAIN.pem

When you generate a wildcard SSL certificate using *.domain.com, it automatically covers all first-level subdomains like:

https://mail.domain.com
https://api.domain.com
https://blog.domain.com

But surprisingly, it doesn't include the root domain (domain.com). This creates a security gap that many developers discover only during production deployment.

The solution lies in properly configuring Subject Alternative Names (SANs) during certificate generation. Here's what happens at the protocol level:

Certificate Field:
- Common Name: *.domain.com
- SANs: [domain.com, *.domain.com]

Modern browsers actually ignore the Common Name field and rely entirely on SANs for validation since Chrome 58 (2017).

Here's how to implement this correctly with different tools:

OpenSSL Configuration

[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no

[req_distinguished_name]
C = US
ST = California
L = San Francisco
O = Your Company
OU = IT
CN = *.domain.com

[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = domain.com
DNS.2 = *.domain.com

Certbot (Let's Encrypt) Example

certbot certonly --manual \
--preferred-challenges=dns \
--agree-tos \
-m admin@domain.com \
-d domain.com \
-d *.domain.com \
--server https://acme-v02.api.letsencrypt.org/directory

AWS Certificate Manager

When requesting a certificate in AWS:

aws acm request-certificate \
--domain-name "domain.com" \
--subject-alternative-names "*.domain.com" \
--validation-method DNS

Azure App Service

For Azure's wildcard certificates, you need to:

  1. Upload a PEM file containing both names
  2. Ensure the certificate's "Hostname" field includes both entries

After implementation, verify with OpenSSL:

openssl x509 -in certificate.crt -text -noout | grep -A 1 "Subject Alternative Name"

Should output:

DNS:domain.com, DNS:*.domain.com
  • Never assume wildcards include root domains
  • Check certificate expiration dates (wildcards often have shorter validity)
  • Remember CDN configurations may need separate certificates

For complex environments needing *.*.domain.com coverage:

[alt_names]
DNS.1 = domain.com
DNS.2 = *.domain.com
DNS.3 = *.*.domain.com

Note: Some CAs restrict multi-level wildcards due to security concerns.