LoginSignup
0
0

サーバ証明書に最低限必要なkeyUsageを調べる

Last updated at Posted at 2024-04-27

はじめに

x509証明書のkeyUsageについて、どの証明書に何を入れていれば動くのかよくわかっていないため、調べてまとめる

keyUsageの種類

keyUsageはRFC5280により定義されている

      KeyUsage ::= BIT STRING {
           digitalSignature        (0),
           nonRepudiation          (1), -- recent editions of X.509 have
                                -- renamed this bit to contentCommitment
           keyEncipherment         (2),
           dataEncipherment        (3),
           keyAgreement            (4),
           keyCertSign             (5),
           cRLSign                 (6),
           encipherOnly            (7),
           decipherOnly            (8) }

それぞれの用途はここが参考になった

証明局の証明書

ルート証明書(および中間証明書)の役割は以下

  • 下位中間証明書もしくはサーバ証明書に署名する
  • crl(証明書失効リスト)に署名する

そのため、証明局用の証明書にはkeyCertSign,cRLSignのみを含めば良いはず
証明書、crl以外に認証のための署名を行う場合はdigitalSignatureも必要になる

サーバ証明書

サーバ証明書の役割は以下

  • サーバが正規ドメインに管理されていることを証明する
    • サーバ証明書内には証明局によるディジタル署名が含まれている
    • クライアントはこれを検証することでサーバ証明書が証明局に発行されていることを検証できる
    • クライアントが検証する分にはkeyUsageを設定する必要がないように思われる
  • 暗号通信を行う
    • TLS通信を行う際、クライアントはサーバ証明書に含まれる公開鍵を用いて共通鍵を作成するためkeyEnciphermentが必要
    • かと思われたが、サーバ証明書から共通鍵を作成するのはセキュリティリスクがありtls1.3から禁止されたそう。
    • https://milestone-of-se.nesuke.com/nw-basic/tls/https-structure/

つまりサーバ証明書にkeyUsageは不要なのでは?と思ったが、TLS暗号化プロセスにおいてサーバが公開鍵に対応する秘密鍵を持っているか証明するために、適当なデータに署名したデータをクライアントに送信するプロセス(CertificateVerify)があるらしい。
そもそもサーバ証明書自身に署名機能がないと秘密鍵を持っている証明ができないので当たり前と言えば当たり前だった。

ここまでのまとめ

証明局のkeyUsageはkeyCertSign,cRLSignを付与し、
TLS通信を行わせたいサーバ証明書のkeyUsageにはdigital Signatureを付与してあげれば最低限動きそう。

やる気になったらkeyUsageの有無による動作検証を行いたい。

実際に検証してみた

# 環境情報
❯ k get node
NAME       STATUS   ROLES                  AGE   VERSION
orbstack   Ready    control-plane,master   16d   v1.27.4+orb1

webサーバの準備

kubernetes上にwebapp Pod,Service,Ingressを立てる

webapp.yaml
❯ cat webapp.yaml 
---
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: webapp
  name: webapp
  namespace: webapp
spec:
  containers:
  - image: nginx:latest
    name: webapp
    ports:
    - name: http
      containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: webapp
  namespace: webapp
spec:
  selector:
    run: webapp
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: http
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: webapp
  namespace: webapp
spec:
  tls:
  - hosts:
    - webapp.k8s.orb.local
    secretName: webapp-cert
  rules:
  - host: webapp.k8s.orb.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: webapp
            port:
              name: http

keyUsageを含まない証明書をマウントする

cat ext.txt 
[req]
subjectAltName= DNS:webapp.k8s.orb.local

❯ openssl x509 -req -in tls.csr -CA ca.crt -CAkey ca.key -days 365 \
  -extensions req -extfile ext.txt -out tls.crt

❯ k create secret tls webapp-cert --cert=tls.crt --key=tls.key -n webapp
webアクセスと証明書のスクリーンショット

image.png

image2.png

Safari/Firefox/Chromeで確認したが、予想に反して、keyUsageを指定しなくても特に怒られずアクセスできた。謎だった。
criticalフラグを付与し忘れていたため、サーバはkeyUsageを無視して署名しているっぽい。

次はkeyUsage=critical,cRLSignを指定して動くか検証する

cat ext.txt 
[req]
subjectAltName= DNS:webapp.k8s.orb.local
keyUsage=critical,cRLSign

❯ openssl x509 -req -in tls.csr -CA ca.crt -CAkey ca.key -days 365 \
  -extensions req -extfile ext.txt -out tls.crt

❯ k delete secret -n webapp webapp-cert
❯ k create secret tls webapp-cert --cert=tls.crt --key=tls.key -n webapp

❯ openssl s_client -connect webapp.k8s.orb.local:443 </dev/null 2&>/dev/null | openssl x509 -noout -ext keyUsage
Warning: Reading certificate from stdin since no -in or -new option is given
X509v3 Key Usage: critical
    CRL Sign

同じようにアクセスできたため、いよいよわからなくなった。

証明書のスクリーンショット(webアクセス画像省略)

Screen Shot 2024-04-29 at 14.37.22-fullpage.png

余談

サーバ証明書が署名しか行わないのであれば、サーバ証明書の鍵ペアは暗号・復号機能を持つRSAではなくEdDSAでいいのではないか?と思い、実際に検証してみたところ、以下エラーでTLS通信が不可能だった。

証明書
❯ openssl s_client -connect webapp.k8s.orb.local:443 </dev/null 2&>/dev/null | openssl x509 -noout -text       
Warning: Reading certificate from stdin since no -in or -new option is given
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            36:1d:7d:ae:00:97:16:60:18:fa:c1:9b:86:f9:af:ce:22:21:db:52
        Signature Algorithm: ED25519
        Issuer: CN=CA Root
        Validity
            Not Before: Apr 29 06:00:31 2024 GMT
            Not After : Apr 29 06:00:31 2025 GMT
        Subject: CN=webapp
        Subject Public Key Info:
            Public Key Algorithm: ED25519
                ED25519 Public-Key:
                pub:
                    0c:b4:35:44:f7:26:c5:bd:16:4a:78:f9:8e:c3:9f:
                    ae:5b:8e:ce:5f:83:e5:df:77:27:d1:17:9b:e0:2f:
                    e2:d6
        X509v3 extensions:
            X509v3 Subject Alternative Name: 
                DNS:webapp.k8s.orb.local
            X509v3 Subject Key Identifier: ...
            X509v3 Authority Key Identifier: ...
    Signature Algorithm: ED25519
    Signature Value: ...

Screen Shot 2024-04-29 at 15.04.01-fullpage.png

RFC8446 を見る限り、ed25519は署名スキームリストに含まれているが、必須でサポートしないといけない署名リストには含まれていないことが原因だと思われる

A TLS-compliant application MUST support digital signatures with
rsa_pkcs1_sha256 (for certificates), rsa_pss_rsae_sha256 (for
CertificateVerify and certificates), and ecdsa_secp256r1_sha256. A
TLS-compliant application MUST support key exchange with secp256r1
(NIST P-256) and SHOULD support key exchange with X25519 [RFC7748].

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0