stylesheet

2023-05-23

オレオレ証明書に SAN (Subject Alternative Name) を追加。

TL;DR: /usr/share/ssl-cert/ssleay.cnf を編集して、make-ssl-cert -f generate-default-snakeoil するべし。

$ sudo cp /usr/share/ssl-cert/ssleay.cnf /usr/share/ssl-cert/ssleay.cnf.org
$ sudo jed /usr/share/ssl-cert/ssleay.cnf

...
[ v3_req ]
basicConstraints        = CA:FALSE
subjectAltName          = @SubjectAltName@, DNS:@HostName@.local, IP:192.168.1.5, IP:192.168.1.6

証明書の作成とwebサーバーの再起動。

$ sudo make-ssl-cert -f generate-default-snakeoil
$ sudo systemctl restart nginx

以上。

以下、結論にたどり着くまでの試行錯誤の記録。

Ubuntu22系のOS、WebサーバーはNginx。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.2 LTS
Release:        22.04
Codename:       jammy

$ sudo lsof -i :80
COMMAND    PID     USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
nginx   130698     root    6u  IPv4 1394269      0t0  TCP *:http (LISTEN)
nginx   130698     root    7u  IPv6 1394270      0t0  TCP *:http (LISTEN)
nginx   130699 www-data    6u  IPv4 1394269      0t0  TCP *:http (LISTEN)
nginx   130699 www-data    7u  IPv6 1394270      0t0  TCP *:http (LISTEN)
nginx   130700 www-data    6u  IPv4 1394269      0t0  TCP *:http (LISTEN)
nginx   130700 www-data    7u  IPv6 1394270      0t0  TCP *:http (LISTEN)

nginxの設定を確認。

$ cat /etc/nginx/sites-enabled/default

# Default server configuration
#
server {
    listen 80 default_server;
    listen [::]:80 default_server;

    listen 443 ssl default_server
    listen [::]:443 ssl default_server;

    include snippets/snakeoil.conf;

    ...
}

snippets/snakeoil.conf をincludeしているのでたどる。

$ cat /etc/nginx/snippets/snakeoil.conf

# Self signed certificates generated by the ssl-cert package
# Don't use them in a production server!

ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;

make-ssl-cert で作成したものだと思うが一応、証明書の内容を確認

$ cat /etc/ssl/certs/ssl-cert-snakeoil.pem | openssl x509 -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            0d:10:12:dd:50:6a:7f:ba:20:7c:61:1f:db:f8:3f:ad:e8:e2:60:6c
        Signature Algorithm: sha256WithRSAEncryption

        ...

make-ssl-cert のマニュアルを確認。

$ man make-ssl-cert
make-ssl-cert(8)                               System Manager's Manual                               make-ssl-cert(8)

NAME
    make-ssl-cert - Debconf wrapper for openssl

SYNOPSIS
    make-ssl-cert [OPTION]... template output-certificate
    make-ssl-cert [OPTION]... generate-default-snakeoil

DESCRIPTION
    make-ssl-cert is a simple debconf to openssl wrapper to create self-signed certificates.  It requires a source
    template (Ex: /usr/share/ssl-cert/ssleay.cnf) and it will place the new generated certificate in the specified
    output file.
    Invoked   with   "generate-default-snakeoil",   it   will  generate  /etc/ssl/certs/ssl-cert-snakeoil.pem  and
    /etc/ssl/private/ssl-cert-snakeoil.key.

...

generate-default-snakeoil では /usr/share/ssl-cert/ssleay.cnf をテンプレートとして使うようだ。

$ cat /usr/share/ssl-cert/ssleay.cnf
#
# SSLeay example configuration file.
#

[ req ]
default_bits            = 2048
default_keyfile         = privkey.pem
distinguished_name      = req_distinguished_name
prompt                  = no
policy                  = policy_anything
req_extensions          = v3_req
x509_extensions         = v3_req

[ req_distinguished_name ]
commonName                      = @HostName@

[ v3_req ]
basicConstraints        = CA:FALSE
subjectAltName          = @SubjectAltName@

v3_reqsubjectAltName で設定できそうだが…。 @SubjectAltName@ ってなんだ?

$ cat /sbin/make-ssl-cert

...

make_snakeoil() {
    if ! HostName="$(hostname -f)" ; then
        HostName="$(hostname)"
        echo "make-ssl-cert: Could not get FQDN, using '$HostName'".
        echo "make-ssl-cert: You may want to fix your /etc/hosts and/or DNS setup and run"
        echo "make-ssl-cert: 'make-ssl-cert generate-default-snakeoil --force-overwrite'"
        echo "make-ssl-cert: again."
    fi
    SubjectAltName="DNS:$HostName"
    if [ ${#HostName} -gt 64 ] ; then
        # The certificate's common name cannot be longer than 64 chars.
        # Use the short name instead.
        HostName="$(hostname)"
    fi
}

create_temporary_cnf() {
    sed -e s#@HostName@#"$HostName"# -e s#@SubjectAltName@#"$SubjectAltName"# "${template}" > "${TMPFILE}"
}
...

sed で置換しているようだ。中身は SubjectAltName="DNS:$HostName" となっているので、ホスト名を設定している。 次は、テンプレート指定の動作について見てみる。

...

# Parse subcommand
if [ "${1}" = "generate-default-snakeoil" ]; then
    subcommand="${1}"
else
    subcommand="manual"
    template="${1}"
fi

...

if [ "${subcommand}" = "manual" ]; then
    if ! openssl req -config "${TMPFILE}" -new -x509 -days "${opt_expiration_days}" -nodes -sha256 \
        -out "${output}" -keyout "${output}" > "${TMPOUT}" 2>&1
    then
        echo "Could not create certificate. Openssl output was:" >&2
        cat "${TMPOUT}" >&2
        exit 1
    fi
    chmod 600 "${output}"
    create_hash_link "${output}"
elif [ "${subcommand}" = "generate-default-snakeoil" ]; then
    if ! openssl req -config "${TMPFILE}" -new -x509 -days "${opt_expiration_days}" -nodes -sha256 \
        -out /etc/ssl/certs/ssl-cert-snakeoil.pem \
        -keyout /etc/ssl/private/ssl-cert-snakeoil.key > "${TMPOUT}" 2>&1
    then
        echo "Could not create certificate. Openssl output was:" >&2
        cat "${TMPOUT}" >&2
        exit 1
    fi
    chmod 644 /etc/ssl/certs/ssl-cert-snakeoil.pem
    chmod 640 /etc/ssl/private/ssl-cert-snakeoil.key
    chown root:ssl-cert /etc/ssl/private/ssl-cert-snakeoil.key
    create_hash_link /etc/ssl/certs/ssl-cert-snakeoil.pem
else
    usage 1
fi

テンプレートを指定した場合は少し動作が異なり、鍵ファイルの配置等は行ってくれない。

面倒なので、/usr/share/ssl-cert/ssleay.cnf を直接編集してしまおう。

$ sudo cp /usr/share/ssl-cert/ssleay.cnf /usr/share/ssl-cert/ssleay.cnf.org
$ sudo jed /usr/share/ssl-cert/ssleay.cnf

...
[ v3_req ]
basicConstraints        = CA:FALSE
subjectAltName          = @SubjectAltName@, DNS:@HostName@.local, IP:192.168.1.5, IP:192.168.1.6

証明書の再生性とnginx再起動。

$ sudo make-ssl-cert -f generate-default-snakeoil
$ sudo systemctl restart nginx

ちなみに、Windowsでは ssl-cert-snakeoil.pem ファイルを「信頼されたルート証明機関」に追加してやれば警告が消える。拡張子を .crt に変更してやると関連付けが効くので、インポートが楽。