概要
PKI(Public Key Infrastructure、公開鍵基盤)とは、デジタル証明書の発行・管理・失効を行う仕組みの総称である。電子証明書(Digital Certificate)は、ある公開鍵が特定の主体(個人、組織、デバイス)に属することを第三者機関(CA: Certificate Authority、認証局)が保証した文書である。
PKI により「この公開鍵は確かに xyz 社のデバイスのものである」という信頼の連鎖(信頼チェーン)が形成される。これにより、インターネット上での安全な通信(HTTPS)、デバイス認証、コード署名などが実現する。
IoT の世界では、数百万台のデバイスそれぞれに固有の証明書を発行・管理する「IoT PKI」が重要課題となっており、自動化されたプロビジョニングと大規模な証明書管理が求められる。
歴史・背景
- X.509 (1988年): ITU-T が X.509 証明書フォーマットを標準化。現在の証明書はほぼすべてこの形式に基づく。
- SSL の登場(1995年): Netscape が SSL(後の TLS)を開発し、HTTPS による安全なウェブ通信が始まった。X.509 証明書が Web 認証の基盤となった。
- RFC 5280 (2008年): インターネット向けの X.509 証明書プロファイルが標準化。現在も使用される基本仕様。
- Let’s Encrypt (2016年): 無料・自動化された証明書発行サービスが開始。証明書の普及が加速した。
- IoT デバイス証明書: AWS IoT、Azure IoT Hub、Google Cloud IoT Core がデバイス証明書を認証手段として採用し、IoT PKI が実用フェーズに入った。
- FIDO2 / Passkey: デバイス内蔵のセキュリティキーをベースにした認証標準が普及し、PKI の概念がエンドユーザー向けにも拡大している。
技術仕様
X.509 証明書の構造
X.509v3 証明書
├── Version: 3
├── Serial Number: 証明書の一意識別番号
├── Signature Algorithm: sha256WithRSAEncryption または ecdsa-with-SHA256
├── Issuer: CN=MyCA, O=MyOrg, C=JP (発行者:認証局)
├── Validity
│ ├── Not Before: 2024-01-01T00:00:00Z
│ └── Not After: 2025-01-01T00:00:00Z
├── Subject: CN=device-001, O=MyOrg, C=JP (証明対象)
├── Subject Public Key Info
│ ├── Algorithm: id-ecPublicKey
│ └── Public Key: (256 bit ECDSA P-256 公開鍵)
├── Extensions(v3 拡張)
│ ├── Subject Alternative Name (SAN): device-001.example.com
│ ├── Key Usage: digitalSignature, keyEncipherment
│ ├── Extended Key Usage: clientAuth, serverAuth
│ ├── Basic Constraints: CA=FALSE
│ └── Authority Key Identifier: CA の識別子
└── Signature: CA による RSA/ECDSA 署名
PKI の構成要素
| コンポーネント | 役割 |
|---|---|
| Root CA | 信頼の最上位。自己署名証明書。オフライン保管が基本 |
| Intermediate CA | Root CA から委任された中間認証局。実際の証明書発行を担当 |
| End Entity Certificate | デバイス・サーバー・ユーザーへの証明書 |
| CRL(証明書失効リスト) | 失効した証明書のリスト |
| OCSP | オンラインでの証明書有効性確認プロトコル |
| RA(登録局) | 証明書申請を受け付け CA に転送 |
証明書の信頼チェーン
[Root CA 証明書] ← 自己署名(デバイスに事前インストール)
↓ 署名
[Intermediate CA 証明書]
↓ 署名
[デバイス証明書] ← デバイス固有。公開鍵の身元を保証
|
└→ 対応する秘密鍵はデバイス内(SE/TPM)に保管
動作原理
TLS ハンドシェイクでの証明書検証
クライアント(IoT デバイス) サーバー(クラウド)
│ │
│ ─── ClientHello ──────────→ │
│ │
│ ←── ServerHello ─────────── │
│ ←── Certificate(証明書)─── │ サーバー証明書を送付
│ ←── ServerHelloDone ──────── │
│ │
│ 証明書チェーンの検証 │
│ 1. 証明書の署名を検証 │
│ 2. 有効期限を確認 │
│ 3. 失効(CRL/OCSP)を確認 │
│ 4. Subject が一致するか確認 │
│ │
│ ─── ClientKeyExchange ─────→ │
│ ─── ChangeCipherSpec ──────→ │
│ ─── Finished ──────────────→ │
│ │
│ 暗号化通信開始 │
デバイス証明書の発行と管理
# 1. 認証局(CA)の作成
# Root CA 鍵ペア生成
openssl genpkey -algorithm EC \
-pkeyopt ec_paramgen_curve:P-256 \
-out root_ca.key
# Root CA 自己署名証明書
openssl req -new -x509 -key root_ca.key \
-out root_ca.crt \
-days 3650 \
-subj "/CN=MyRootCA/O=MyCompany/C=JP"
# 2. デバイス証明書の発行
# デバイス鍵ペア生成(実際はデバイス上で生成)
openssl genpkey -algorithm EC \
-pkeyopt ec_paramgen_curve:P-256 \
-out device_001.key
# CSR(証明書署名要求)作成
openssl req -new -key device_001.key \
-out device_001.csr \
-subj "/CN=device-001/O=MyCompany/C=JP"
# CA が署名して証明書発行
openssl x509 -req -in device_001.csr \
-CA root_ca.crt -CAkey root_ca.key \
-CAcreateserial \
-out device_001.crt \
-days 365 \
-extfile <(echo "subjectAltName=DNS:device-001")
Python での証明書検証
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.x509.oid import NameOID
import datetime
def verify_certificate_chain(device_cert_pem: bytes,
ca_cert_pem: bytes) -> bool:
"""証明書チェーンの検証"""
device_cert = x509.load_pem_x509_certificate(
device_cert_pem, default_backend())
ca_cert = x509.load_pem_x509_certificate(
ca_cert_pem, default_backend())
# 有効期限確認
now = datetime.datetime.utcnow()
if now < device_cert.not_valid_before or now > device_cert.not_valid_after:
print("証明書が期限切れまたは未有効")
return False
# CA の署名検証
try:
ca_cert.public_key().verify(
device_cert.signature,
device_cert.tbs_certificate_bytes,
device_cert.signature_hash_algorithm
)
print("署名検証: OK")
return True
except Exception as e:
print(f"署名検証失敗: {e}")
return False
def get_device_common_name(cert_pem: bytes) -> str:
"""証明書から CN を取得"""
cert = x509.load_pem_x509_certificate(cert_pem, default_backend())
return cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value
AWS IoT Core へのデバイス接続
import boto3
import ssl
import paho.mqtt.client as mqtt
# デバイス証明書を使った MQTT 接続
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
context.load_verify_locations('AmazonRootCA1.pem') # AWS Root CA
context.load_cert_chain(
certfile='device_001.crt', # デバイス証明書
keyfile='device_001.key' # デバイス秘密鍵(実際は SE に保管)
)
client = mqtt.Client()
client.tls_set_context(context)
client.connect('your-endpoint.iot.ap-northeast-1.amazonaws.com', 8883)
client.publish('devices/device-001/telemetry', '{"temp": 25.3}')
用途・ユースケース
HTTPS(Web サーバー認証)
ブラウザがサーバーの証明書を検証し、正規のサーバーと通信していることを確認する。CA(DigiCert、GlobalSign、Let’s Encrypt など)が信頼の起点となる。
IoT デバイス認証
各 IoT デバイスに固有の X.509 証明書を発行し、クラウドへの接続時にデバイスの身元を証明する。秘密鍵をセキュアエレメントやTPMに保管することで、証明書の不正利用を防ぐ。
コード署名
ファームウェアや ソフトウェアの配布元を証明する。Microsoft Authenticode、Apple Developer ID、Android APK 署名などがこれに当たる。
VPN・社内ネットワーク
企業の VPN 接続でクライアント証明書を使ったデバイス認証を行い、認定された端末のみ社内ネットワークへの接続を許可する。
実装・開発のポイント
IoT での証明書ライフサイクル管理
[製造時]
デバイス上で鍵ペア生成(SE 内)
CSR 生成 → 製造 CA へ送付
製造 CA が証明書発行
証明書をデバイスに書き込み
[運用時]
クラウドへの接続に証明書を使用
証明書の有効期限監視
更新期限前に EST (RFC 7030) で自動更新
[廃棄時]
証明書の失効申請(CRL への追加)
秘密鍵の消去(SE のライフサイクル終了)
証明書の有効期限管理
組み込みデバイスは長期間フィールドに展開されるため、証明書の有効期限切れが問題になりやすい。一般的な対策:
| 対策 | 方法 |
|---|---|
| 長期証明書 | 10〜20 年の有効期間(セキュリティリスクとのトレードオフ) |
| 自動更新 | EST (RFC 7030) や ACME (RFC 8555) プロトコルで自動更新 |
| 証明書ピンニング | 特定の CA/証明書のみ信頼(柔軟性は下がる) |
| OTA 更新 | OTA で証明書を更新(鍵の更新も含む) |
大規模デバイス管理
数万〜数百万台のデバイスへの証明書一括発行には、専用の IoT PKI サービスを活用する。
- AWS IoT: Just-in-Time Provisioning (JITP) で自動証明書発行
- Azure IoT Hub: DPS(Device Provisioning Service)で自動登録
- Keyfactor、Venafi: エンタープライズ IoT PKI ソリューション
他技術との比較
| 認証方式 | 強度 | スケール | 管理コスト | IoT 適性 |
|---|---|---|---|---|
| X.509 証明書 / PKI | 高 | 大規模可能 | 高(自動化必要) | 最適 |
| 事前共有鍵(PSK) | 中 | 低(鍵の共有が困難) | 低 | 小規模向け |
| JWT / API キー | 低〜中 | 大規模可能 | 低 | クラウド向け |
| ユーザー名・パスワード | 低 | 中 | 低 | 不適(デバイス向けではない) |
PKI は公開鍵暗号の実用基盤であり、TLS/DTLSの信頼性の根拠となる。IoT セキュリティの実装において、PKI の理解と適切な運用は不可欠な要素である。