概要
Things CloudのMQTT実装には、次の利点があります。
- マルチテナントのサポート: 1つのエンドポイントが複数のテナントに対応します。
- デバイスID管理: デバイス固有の認証情報を使用してデバイスを認証します。
- デバイス登録: カスタマイズしていない非パーソナライズなデバイスは、Things Cloudテナントとペアリングすることでご利用可能となります。
- デバイス管理: 定義済みの豊富なデバイス管理ペイロード形式により、多数のデバイスを簡単に管理できます。
- 標準IoTペイロード形式: IoTセンサーの読み取り、アラーム管理、リモートコントロール、デバイス階層をサポートするために事前定義されたペイロード形式です。
- カスタムペイロード形式: ペイロード形式を追加できます。
- トラフィックオーバーヘッドを小さくできます。
- 処理モード: データをThings Cloudデータベースに保存する、リアルタイム処理に一時的に渡す、リアルタイム通知を無効化にする QUIESCENT モードを使用して処理する、リアルタイム通知が無効化された場合にのみデータをリアルタイム処理エンジンに一時的に送信する CEP モードを使用して処理する、のいずれかを制御します。
- 完全な双方向通信が可能で、デバイス、サーバー間のメッセージを簡単に送受信できます。
- WebソケットのMQTT接続をサポートします。
- TLSをサポートします。
- 完全な水平方向の拡張性をサポートします。
MQTTセクションの構造は次の通りです。
- MQTT実装では、MQTTのThings Cloud実装におけるプロトコル・レベルの側面について詳細なリファレンスを提供します。
- デバイスインテグレーションでは、MQTTを使って、デバイスとThings Cloudをインターフェースさせるプロセスを順を追って説明します。
- デバイス証明書 では、デバイスが証明書を使用して MQTT 経由で接続する方法について説明します。
SmartREST ドキュメント もご覧ください。
このセクションでは、MQTT通信の基本については説明しません。MQTTに慣れていない場合は、インターネットにある数多くの入門書等を参照することをお勧めします。参考文献のいくつかはMQTTのWebサイトにございます。
MQTT実装
このセクションでは、MQTTプロトコルの実装の詳細を一覧表示します。Things Cloudの実装は MQTTバージョン3.1.1をサポートしています。
MQTT標準接続
Things CloudはTCPとWebソケットの両方でMQTTをサポートしています。URLとして、利用しているテナントのドメイン(例: mytenant.je1.thingscloud.ntt.com/mqtt )、もしくは次の形式のインスタンスのドメイン mqtt.<instance_domain> を利用できます(例: mqtt.je1.thingscloud.ntt.com)。
使用可能なポート:
TCP | Webソケット | |
---|---|---|
一方向SSL | 8883 | 443 |
ポート 8883 は、クライアント認証に証明書を使用する双方向 SSL と、クライアント認証にユーザー名とパスワードを使用する一方向 SSL の 2 種類の SSL をサポートします。 双方向 SSL サポートはデフォルトで有効になっています。 無効にするには、製品サポート にお問い合わせください。
SmartRESTペイロード
Things Cloud MQTT実装は、SmartRESTをペイロードとして使用します。
SmartRESTはCSVに似たメッセージプロトコルで、サーバーサイドのテンプレートを使用してThings Cloudでデータを作成します。 REST APIの高い表現力を取り入れていますが、組み込みデバイスのJSON解析の複雑さを回避するために、JSONをカンマ区切り値(CSV)に置き換えています。 さらに、CSVのシンプルでコンパクトな構文により、モバイルネットワークを介したIoT通信でも非常に効率的です。 他のHTTP APIと比較して、モバイルトラフィックを最大80%節約できます。
SmartRESTの基本
SmartRESTメッセージは、各パラメータがカンマで区切られた1行です。最初のパラメータは、メッセージを定義するIDです。メッセージ間に改行を使用すると、一度のパブリッシュで複数のメッセージを送信できます。
SmartRESTエスケープ
SmartRESTエンドポイントとの通信には、CSV(カンマ区切り値)形式を使用します。正常に通信するためには以下の規則に従う必要があります。
- すべての行は
\n
で終了する必要があります - 値は常にカンマ (
,
) で区切られている必要があります - 値が二重引用符 (
"
)、カンマ (,
)、前後の空白、改行 (\n
)、キャリッジリターン (\r
)、タブを含む場合、二重引用符 ("
) で囲む必要があります。二重引用符 ("
) を含む文字は別の二重引用符 (""
) を先頭に付与してエスケープする必要があります
サーバーからクライアントに送信されるメッセージにも同様のエスケープ規則が適用されます。
パブリッシュの例:
100,"This value, needs escaping",This value does not need escaping
サブスクライブの例:
511,myDeviceSerial,"execute this\nand this\nand ""this"""
\n
は出力(例: コンソールやUI)中では新規の行を作成しません。新規の行を作成するには、改行文字(ASCII 0A)を使用する必要があります。デバイス階層
MQTTセッションは1つのデバイスにリンクされますが、このデバイスの下には自由に設定可能なデバイス階層を持つことができます。
すべての子デバイスには、デバイスの作成時に定義された一意のIDが必要です。ルートデバイスの一意のIDと階層内の一意のIDを組み合わせて使用することをお勧めします。
ルートデバイスの代わりに子デバイスのデータを作成するには、子デバイスの一意のIDをトピックの別のセクションとして追加します(例: s/us/myChildDeviceIdentifier)。
クライアントは、それぞれのトピックをサブスクライブすることにより、階層内のすべての子デバイスに対するオペレーションを自動的に受信します。子デバイスごとにサブスクライブする必要はありません。
受信されたすべてのオペレーションには、テンプレートIDの後に、そのオペレーションが作成されたデバイス/子デバイスのIDが含まれます(その後に他のオペレーションパラメータが続きます)。
MQTT機能
MQTT認証
MQTT を使用した Things Cloud との通信は、次の 2 つの方法で認証をサポートしています。
- ユーザー名とパスワード。 MQTT ユーザー名には、テナント ID とユーザー名を <tenantID/username> の形式で含める必要があります。
- デバイス証明書。 デバイスには、信頼されたルート証明書につながる証明書のチェーン全体が含まれている必要があります。 また、トラストストアにサーバー証明書が含まれている必要があります。
トラブルシューティング
デバイスから正しいユーザー名とパスワードが送信されるが、同時に不正な証明書も送信される
プラットフォームが双方向 SSL をサポートするように構成されており、デバイスに無効な証明書を含む構成されたキーストアがあり、基本認証を使用したい場合は、接続中に証明書の送信をオフにすることをお勧めします。 証明書の有効期限が切れているか、ルート証明書がプラットフォームにアップロードされていないため、証明書が無効である可能性があります。 デバイスのソフトウェアでの証明書の送信をオフにしてください。 それが不可能な場合、接続を機能させるには次の点を確認してください。
- プラットフォームのトラストストアを空にすることはできません。 少なくとも 1 つの信頼できる証明書をプラットフォームにアップロードする必要があります。
- デバイスの MQTT クライアントは、ハンドシェイク中にサーバーから返された承認された発行者リストにルート証明書が見つからない場合、証明書を送信しないように構成する必要があります。 ほとんどの場合、これは自動的に行われます。 MQTT クライアントと Java 11 では動作しないことが知られていますが、Java 8 では動作します。
- この状況をサポートするには、プラットフォームをそれに応じて構成する必要があります。 問題が発生した場合は、製品サポート までお問い合わせください。
- 上記のすべてのケースが満たされているにも関わらず、証明書の検証によりデバイス接続が拒否される場合は、おそらく他のテナントが、デバイスから送信された証明書の 1 つと同じ「コモンネーム」を持つ証明書をアップロードした可能性があります。 この場合、デバイスは常に証明書を使用して独自に認証しようとします。
MQTT ClientId
MQTT ClientIdは、接続されている各クライアントを一意に識別するフィールドです。Things Cloud実装もClientIdを使用して、クライアントを直接デバイスにリンクします。したがって、ClientIdには次の形式を使用する必要があります。
connectionType:deviceIdentifier:defaultTemplateIdentifier
フィールド | 必須 | 説明 |
---|---|---|
connectionType | いいえ | 接続タイプのデフォルト表示: d (デバイス) |
deviceIdentifier | はい | デバイスの一意の識別子 (IMEI, シリアル番号など) |
defaultTemplateIdentifier | いいえ | テンプレート識別子の詳細については、SmartREST 2.0 > MQTT 静的テンプレートをご覧ください |
クライアントの最も単純なバージョンでは、MQTT ClientIdは単に deviceIdentfier
にすることができます。デバイス接続として自動的に解釈されます。
deviceIdentfier
では使用しないでください。ClientIdの例:
mySerialNumber
d:mySerialNumber
d:mySerialNumber:myDefaultTemplate
MQTT ClientIdの一意性は、deviceIdentfier
によってのみ決定されます。したがって、上記の例では、同時に接続できるクライアントは1つだけです。
証明書によるSSL接続では、deviceIdentfier
は使用されている証明書(デバイスにより提供される証明書チェーンのうち最初のもの)の「コモンネーム」と一致している必要があります。
MQTTサービス品質 (QoS)
Things Cloud実装は、MQTT QoSの3つのレベルすべてをサポートします。
- QoS 0: 最大1回
- クライアントは一度だけメッセージを送信します。
- サーバーからの応答はありません。
- QoS 1: 1回以上
- クライアントはサーバーからの確認応答を受け取るまでメッセージを送信し続けます。
- QoS 2: 1回のみ
- クライアントはメッセージを送信します。
- サーバーは確認応答を返します(メッセージは保持されます)。
- クライアントはリリースコマンドを送信します。
- サーバーはメッセージを処理し、再度確認応答を返します。
オペレーショントピックまたはエラートピックをサブスクライブする場合は、トピックのサブスクライブ時にクライアントが定義したQoS内のすべてのメッセージを配信します。
MQTTクリーンセッション
Things Cloudはクリーンセッションを「1」(true)に設定する必要があります。現在のところ、クリーンセッションを無効にしても完全に動作することは保証できませんので、常にクリーンセッションを有効にすることを推奨します。
MQTT保持フラグ
現在のThings Cloud実装では、デバイスがデータをパブリッシュするトピックへのサブスクリプションは許可されていません。このトピックに保持フラグを付けてデータをパブリッシュすることはできますが、フラグを付けずにデータを送信することと実質的な違いはありません。 Things Cloudがパブリッシュするオペレーションやエラーなどのメッセージには、保持フラグは含まれません。
MQTT last will
MQTTでは、「last will」は接続時に指定し、クライアントが接続を失ったときに実行されるメッセージです。例えば、last willメッセージとして 400,c8y_ConnectionEvent,"Device connection was lost."
、last willトピックとしてs/usを指定すると、デバイスが接続を失うたびにイベントが発生します。
MQTT リターンコード
MQTT エラーが発生した場合、プラットフォームはゼロ以外のリターンコードを含むCONNACK
メッセージで応答します。
このメッセージは、問題があることを示す最初の手がかりです。
このようなリターンコードは、401 などの REST API HTTP コードと同様に扱うことができます。
これらは、予期しないエラーや権限の不足などの理由で返される可能性があります。
CONNACK
は、CONNECT
メッセージに対する応答であるだけでなく、プラットフォームで発生したエラーを通知する方法でもあります。
したがって、通常の接続中に直接アクションを行わなくても、このメッセージを 2 回目に受信する可能性があります。
ほとんどの MQTT クライアントは、接続を閉じる必要があるかのように0
以外のコードで CONNACK
を扱うため、これは接続の終了を知らせる方法でもあります。
詳細は以下をご覧ください。
以下の表は、Things Cloud によって返されるエラーのリストを示しています。
コード | 正規メッセージ | トラブルシューティング |
---|---|---|
0 | Connection accepted | 問題ありません。接続は機能しています。 |
1 | Connection refused, unacceptable protocol version | MQTT プロトコルのサポートされていないバージョン。 現在、Things Cloud では 3.1 と 3.1.1 のみが許可されています。 |
2 | Connection refused, identifier rejected | ClientId がプラットフォームに受け入れられません。 |
3 | Connection refused, Server unavailable | 一般的なプラットフォーム側のエラー。内部エラーや不明な認証の問題で受信されることもあります。 ネットワークの問題で受信できます。 このエラーは一時的なものでありデバイスの状態とは無関係であるため、通常の解決策は後で再試行することです。 |
4 | Connection refused, bad username or password | 認証情報が正しくありません (パスワードが空ではありませんが、ユーザー名やパスワードが間違っています)。 証明書を使用して認証する場合、このエラーが返されることはありません。 |
5 | Connection refused, not authorized | ほとんどがデバイス側に関連した問題で、デバイスにアクセス許可がない、または禁止されている操作を行っている場合に使用されます。例えば、クライアントが不正なメッセージを送信したり、メッセージの公開など、最初に認証を行わずに操作を実行しようとした場合などです。 証明書の認証に関する問題 (コモンネームが間違っている、自動登録が失敗したなど) が発生した場合にスローされます。 また、デバイス データの受信に関する一般的な問題や、プラットフォーム上のデバイスの状態に関連するその他の認証の問題でもスローされます。 例えば、デバイスのマネージドオブジェクト問題や、アクセス権限が突然削除された場合などです。この状況では、プラットフォーム上で調査と修正の適用を行う必要がある場合があります。 MQTT バージョン 3.1 を使用している場合、clientId が長すぎると、このエラーが発生する可能性があります。 これは、clientId が 24 文字以上の場合に発生する可能性があります。 最後に、特に接続中のパフォーマンスの問題など、予期しない例外が発生した場合にもスローされる可能性があります。 したがって、一時的なパフォーマンスの問題を解決するには、接続を数回繰り返すことが良い方法です。 |
公式の MQTT 接続リターン コードの詳細については、MQTT バージョン 3.1.1 > 3.2 CONNACK - Acknowledge connection request をご覧ください。
デバッグ
開発中に開発者をサポートするために、トピックs/eをサブスクライブできます。このトピックでは、デバイスからパブリッシュ中に発生するデバッグメッセージおよびエラーメッセージを取得できます。
MQTT ブローカー証明書
MQTT ブローカーは、メイン環境ドメインに割り当てられた証明書を使用します。 MQTT ブローカーは、常にTLS ハンドシェイク中に、これらの証明書をデバイスに送信します。
デバイスインテグレーション
概要
デバイスをThings Cloud に統合するための基本的なライフサイクルについては、デバイスのインターフェースで説明しています。
このセクションでは、MQTT実装を使用してこのライフサイクルを管理する方法を説明します。
ライフサイクルは、起動フェーズとサイクルフェーズの2つのフェーズで構成されます。
起動フェーズは、認証情報を確認するだけで済みます。
- ステップ0: デバイス認証情報がまだリクエストされていない場合はリクエストします。
- ステップ1: デバイスがすでに登録されているかどうかを確認します。
- ステップ2: 子デバイスが存在するかどうかを確認します。
- ステップ3: トピックをサブスクライブします。
サイクルフェーズは、次の2種類のアクションで構成されます。
スタートアップフェーズ
ステップ0: デバイスの認証情報をリクエストする
Things Cloudでは、すべてのMQTT接続を認証する必要があります。MQTT実装のデバイス認証トピックを使用して、デバイスの新しい認証情報を生成できます。
Things Cloudが提供している静的認証情報を使ってデバイスが認証情報を取得したら、その認証情報をローカルに保存して、取得した認証情報を使い接続する必要があります。
接続を確立するには、次のパラメータを構成する必要があります。
- ホスト: <your_tenant_url>
- ユーザー: <tenantID>/<username>
- パスワード: <password>
詳細については、Hello MQTTセクションをご覧ください。
プロセスは次の通りです。
- Things Cloudは、各デバイスが何らかの形式の固有IDを持っていると仮定します。例えば、適切なデバイス識別子は、ネットワークアダプタのMACアドレス、モバイルデバイスのIMEI、またはハードウェアのシリアル番号です。
- 新しいデバイスを使用するときは、この固有のIDをThings Cloudのデバイス管理アプリのデバイス登録に入力し、デバイスを起動します。
- デバイスは、MQTT ClientIdの一部としてこのIDを使用します。Things Cloudでは静的認証情報を提供しており、製品サポートにて問い合わせることができます。
- デバイスは、トピックs/dcrをサブスクライブします。
- デバイスは、トピックs/ucrに連続した空のメッセージのパブリッシュを開始し、認証情報を取得する準備ができたことをサーバーに通知します。
- 次に、デバイス登録ページでデバイスからの接続を承認する必要があります。
- デバイスが次の空のメッセージを送信すると、
70,<tenantID>,<username>,<password>
の形式の認証情報を受け取ることができます。
認証情報を受信した後、デバイスはMQTT接続を閉じて、受信した認証情報で新しい接続を作成できます。
ステップ1: デバイスを確認する
クライアントがデータを送信しデバイスが存在しないときに MQTTはデバイスの自動作成をサポートするため、このステップはデバイスを手動で作成する場合にのみ必要です。
デバイスの作成は、静的テンプレート100を使用することで実現できます。このテンプレートは、デバイスがまだ存在しない場合にのみ作成するため、デバイスのブートのたびに何もせずに使用できます。
デバイスは、クライアントがMQTT ClientIdで使用するIDに自動的にリンクされます。
100,Device Name,Device Type
ステップ2: 子デバイスを確認する
ルートデバイスと同様に、その子デバイスも自動デバイス作成の対象となります。
このステップを手動で行うには、子デバイスを作成するための静的テンプレート101を送信します。テンプレートは、子デバイスが存在しない場合にのみ作成します。
101,Unique Child ID,Child Name,Child Type
ステップ3: トピックをサブスクライブする
デバイスがオペレーションをサポートしている場合は、必要なすべてのトピック(静的テンプレートおよびSmartREST 2.0)をサブスクライブする必要があります。
サイクルフェーズ
ステップA: CSVデータを送信する
デバイスはアクティブなMQTT接続を保持していますが、静的テンプレートのトピックまたはSmartRESTテンプレートのトピックのいずれかでパブリッシュして、サーバーにデータを送信できます。
MQTT ClientIdに基づいて、物理デバイスはThings Cloud内のデバイスオブジェクトに直接接続されます。したがって、送信するデータは自動的にデバイスに接続されます。
子デバイスにデータを送信するには、デバイス階層で説明されているトピックにデータをパブリッシュします。
ステップB: CSVオペレーションを受信する
トピックをサブスクライブすると、デバイスは自動的にThings Cloudにオペレーションを受け取りたいことを伝えます。作成されたオペレーションは、静的テンプレートまたはデバイスが定義するテンプレートを使用して自動的に解析されます。
デバイス証明書
概要
デバイスは、X.509 クライアント証明書を使用して Things Cloud プラットフォームに対して認証を行えます。
デバイスはプラットフォームの MQTT インターフェースを使用して通信できますが、WebSocket 上のMQTT はサポートされていません。Things Cloudプラットフォームは、デバイスがポート8883でSSLを使用して接続することを想定しています。
各テナントは、ベースCA証明書をアップロードすることで、誰を信頼するかを個別に定義しています。
証明書を使ってプラットフォームに接続するデバイスは、テナントID、ユーザー名、パスワードを提供する必要はありません。認証情報は、証明書から取得されます。
証明書を使用してデバイスを接続するための一般的な要件
- CA 証明書は自己署名証明書である場合もあります。
- 証明書は X.509 バージョン 3 証明書としてアップロードする必要があります。
- アップロードされた証明書は、
BasicConstraints:[CA:true]
が設定されている必要があります。 - 証明書のコモンネームには
:
文字を含めることはできません。詳細については、 MQTT ClientIdをご覧ください。 - デバイスは Things Cloud サーバー証明書を信頼する必要があります。
- デバイスで使用される証明書には、アップロードされた CA 証明書を含む証明書チェーンが含まれている必要があります。
- デバイスで使用される証明書は、アップロードされた CA 証明書、またはアップロードされた CA 証明書によって署名された中間証明書によって署名される必要があります。
証明書を使用したデバイス登録
Things Cloudでは、証明書を使って接続するデバイスを登録する方法として、以下の2つの方法をサポートしています。
自動登録
デバイス証明書が、true の値を持つ autoRegistrationEnabled フラグで Things Cloud プラットフォームにアップロードされた信頼できる証明書から派生する場合、デバイスのユーザーは最初の MQTT コール中に作成されます。 アップロードされた証明書に対して自動登録を有効にする必要があります。 自動登録が有効になっていない場合は、一括登録を使用する必要があります (下記参照)。 UIでアップロードされた証明書の自動登録フィールドを管理するには、デバイス管理 > デバイスデータの管理 > 信頼できる証明書の管理をご覧ください。
一括登録
デバイスのユーザーは、デバイス管理アプリの標準的な一括登録からも作成することができます。
一括登録で使用するCSVファイルは、Things Cloud OpenAPI仕様の一括デバイス認証情報リクエストを作成するに記載されている要件を満たしている必要があります。また、CSVファイルには、CERTIFICATES の値を持つAUTH_TYPE列が追加されており、CREDENTIALS列が存在しないか、値が空であることが必要です。
単一登録
単一登録は、認証に証明書を使用するデバイスではサポートされていません。
JWTトークンの取得
証明書によって認証され、Things Cloud プラットフォームに接続されているデバイスは、後で HTTP リクエストの認証に使用できるトークンを受け取ることができます。
- まず、デバイスはトピック s/dat をサブスクライブします。
- 次に、デバイスはトピック s/uat に空のメッセージをパブリッシュします。
- しばらくすると、トークンがサブスクライブされた s/dat トピックに次の形式で公開されます。
71,<<Base64 encoded JWT token>>
デバイストークンの有効期限は、テナントオプションで設定することができ、カテゴリは oauth.internal
、キーは device-token.lifespan.seconds
です。
デフォルト値は1時間で、最小許容値は5分です。
詳細は、Things Cloud OpenAPI仕様のTenant APIを参照してください。
デバイスは、トークンの有効期限の半分が経過した後に JWT トークンをリクエストした場合、古いデバイストークンの有効期限が切れる前に新しいデバイストークンを取得できます。
X.509 証明書の概要
X.509 は公開鍵証明書を定義する標準であり、安全な接続とデータ転送を提供するために SSL プロトコルで一般的に使用されます。 バージョン 3 が 1995 年以降の最新です。
X.509 証明書の一般的な目的は、ID を鍵のペアにバインドすることです。公開鍵は証明書の一部として公開され、秘密鍵は証明書の所有者のみが知ることができます。 このような鍵のペアは、現在では安全であると考えられている非対称鍵アルゴリズムで作成する必要があります。 このようなアルゴリズムの例として、少なくとも2,048ビットのキーサイズを持つRSAがあります。 1,024ビット以下は、もはや安全とは見なされません。 秘密鍵は、2つの方法で使用することができます。
- メッセージが証明書の所有者によって送信されたことを証明する
所有者は、秘密鍵を使用してメッセージを暗号化して送信します。 その後、受信者は送信者の公開鍵を使用してそれを復号化できます。 復号化されたメッセージが期待通りであれば、それが証明書の所有者によって送信されたものであると確信できます。 - 証明書所有者のみを対象としたメッセージを読む
誰かが受信者の公開鍵を使用してメッセージを暗号化した場合、秘密鍵の所有者だけがメッセージを復号化できます。 何らかの方法でメッセージを傍受した第三者はメッセージを読むことができません。
すべての証明書は自己署名することも、別の証明書で署名することもできます。 証明書が自己署名であるかどうかを確認するには、証明書の「発行者名」フィールドと「サブジェクト名」フィールドを確認します。 この2つが同じであれば自己署名証明書であることを意味し、そうでなければ、証明書は発行者によって署名されていると主張します。 発行者が本当に証明書に署名したかどうかを確認するには、証明書の「署名」フィールドを確認する必要があります。 発行者の公開鍵で復号化した後、署名は署名された証明書のデータと一致するはずです。 別の人が証明書に署名するということは、発行者の証明書が信頼できる場合は、署名された証明書も信頼できることを意味します。
例えば、プラットフォームがお客さまの証明書を信頼しており、お客さまが個別の証明書を持つ 20 台のデバイスを持っている場合、それらを 1 つずつアップロードする必要はありません。
これらのデバイス証明書がお客さまの証明書によって署名されている場合、プラットフォームはそれらも信頼する必要があります。 この場合、すべてのデバイスは、SSL ハンドシェイク中に独自の証明書だけでなく、証明書のチェーン全体 (いわゆる信頼のチェーン) を送信する必要があります。
証明書のチェーンは、デバイスに属する証明書から始まり、プラットフォームによって信頼される CA 証明書に到達するまで、使用されるすべての中間証明書を経由します。 通常、証明書のチェーンには信頼できる CA 証明書が含まれている必要はないため、CA によって直接署名された証明書で終わることができます。 しかし、Things Cloud プラットフォームでは、証明書チェーンに信頼できる CA 証明書を提供することも必要です。
証明書のチェーンを提供すると、プラットフォームはチェーン内のすべての証明書の署名を検証して、デバイス証明書が信頼された証明書によって直接または間接的に署名されていることを確認できます。 証明書のチェーンの長さは異なる場合があるため、プラットフォームが証明書 A を信頼し、証明書 B が A によって署名され、証明書 C が B によって署名されている場合、証明書 C も信頼されます。 ただし、注意すべき点がいくつかあります。
- 別の証明書の署名に使用されるすべての証明書には、拡張の「CA:TRUE」が含まれている必要があります。
- 証明書のチェーンの長さは、証明書の拡張「pathlen」によって制限できます。 この拡張機能は、デバイス証明書とその拡張機能を持つ証明書との間のチェーンに配置できる他の CA 証明書の量を制限します。例えば、パス長の最小値を持つ有効な証明書のチェーンは次のようになります。
「A (CA:TRUE, pathlen: 2) -> B (CA:TRUE, pathlen: 1) -> C (CA:TRUE, pathlen: 0) -> D (device with CA:FALSE)」
バージョン3のX.509証明書の構造は、以下のようになります。
- Version - x.509 証明書のバージョン番号
- Serial Number - 発行者が作成する証明書ごとに作成される一意のシリアル番号
- Issuer - 発行者の識別名
- Not Before - 証明書が有効になった日付
- Not After - 証明書の有効期限
- Subject - 証明書の所有者の識別名
- Public Key Algorithm - 公開鍵の生成に使用されるアルゴリズム
- Subject Public Key - 公開鍵の値
- Certificate Signature Algorithm - 証明書署名の生成に使用されるアルゴリズム
- Certificate Signature - 証明書データを発行者の秘密鍵で暗号化することにより生成される証明書署名
- Extensions(任意) - 例として、証明書が CA である場合、別の証明書の署名に使用できることを意味するなど、さまざまな情報を提供する役割を担っています。X.509 のバージョン 3 で追加されました。
- Issuer Unique Identifier(任意) - 発行者名の再利用の可能性に対応するため、証明書に記載することができます。
- Subject Unique Identifier(任意) - サブジェクト名の再利用の可能性に対応するため、証明書に記載することができます。
X.509 証明書による認証がどのように機能するかを示すために、簡略化された相互 SSL ハンドシェイクの例を示します。
サーバーは、クライアントの公開鍵を使用してメッセージの暗号化されたコピーを復号化した後、クライアントが送信した証明書の所有者であることを認識します。 サーバーが正しいセッションキーを使用している場合、クライアントは、サーバーが秘密鍵を使用して証明書を復号化したことを意味するため、送信した証明書の所有者がサーバーであることを認識します。 ユーザー名とパスワードによる Basic 認証では、ユーザーを認証するためにパスワードをネットワーク経由で送信する必要があります。 証明書を使用する場合、秘密鍵は送信されないため、証明書の使用はユーザー名とパスワードによる Basic 認証よりもはるかに安全になります。
X.509証明書には3つの重要な用語があり、これからX.509証明書を使う人は誰もが知っておく必要があります。
- キーストアは、相互 SSL ハンドシェイクでデバイス自体を認証するために使用するファイルです。 つまり、キーストアには、デバイスで使用される証明書のチェーンとデバイスの秘密鍵が含まれています。
- トラストストアは、信頼できるすべての証明書が含まれるファイルです。サーバーまたはデバイスは、トラストストアからの証明書を使用するもののみと接続を確立します。 証明書のチェーンを使用する場合、接続を確立するにはチェーン内の証明書のうち 1 つだけを信頼する必要があります。
- 最も単純な意味での認証局 (CA) は、証明書に署名する機関です。
キーストアとトラストストアは同じファイルに保存できますが、セキュリティ上の理由から、別々に保存することをお勧めします。 トラストストアには公開データが含まれ、キーストアには所有者のみが知る必要がある秘密鍵が含まれます。 これらのファイルの最も一般的な形式は次のとおりです。
- PKCS12 (Public Key Cryptography Standards, version 12):OpenSSL ツールキットを使用して生成できます。
- JKS (Java KeyStore) :Java Keytoolで生成できます。
証明書の生成と署名
証明書を生成するには、OpenSSL ツールキットを使用します。 まだインストールしていない場合は、次のWebサイトからダウンロードすることができます。
https://www.openssl.org/source/
自己署名CA証明書の作成
-
ルート証明書と署名構成用のディレクトリを作成します。次に例を示します。
mkdir /home/user/Desktop/caCertificate
-
作成したディレクトリに移動し、CA 証明書の構成ファイルを作成します。
touch caConfig.cnf
-
CAによって署名された証明書の履歴を保持するためのデータベースファイルを作成します。
touch database.txt
-
署名付き証明書の識別に使用される初期シリアル番号を含むシリアルファイルを作成します。このシリアルを署名付き証明書に割り当てると、このファイル内の値が自動的に増加します。
echo 1000 > serial
-
署名付き証明書と証明書失効リスト用のサブディレクトリを作成します。
mkdir deviceCertificates crl
-
設定ファイルに記入します。 これは設定例であり、ディレクトリ
dir
を独自のディレクトリに変更した後、テストに使用することができます。 本番環境で使用する場合は、まずセキュリティーの専門家に相談してください。[ ca ] default_ca = CA_default [ CA_default ] # Directory and file locations. dir = /home/user/Desktop/caCertificate certs = $dir # directory where the CA certificate will be stored. crl_dir = $dir/crl # directory where the certificate revocation list will be stored. new_certs_dir = $dir/deviceCertificates # directory where certificates signed by CA certificate will be stored. database = $dir/database.txt # database file, where the history of the certificates signing operations will be stored. serial = $dir/serial # directory to the file, which stores next value that will be assigned to signed certificate. # The CA key and CA certificate for signing other certificates. private_key = $dir/caKey.pem # CA private key which will be used for signing certificates. certificate = $dir/caCert.pem # CA certificate, which will be the issuer of signed certificate. default_md = sha256 # hash function default_days = 375 # default number of days for which the certificate will be valid since the date of its generation. preserve = no # if set to 'no' then it will determine the same order of the distinguished name in every signed certificate. policy = signing_policy # the name of the tag in this file that specifies the fields of the certificate. The fields must be filled in or even match the CA certificate values to be signed. # For certificate revocation lists. crl = $crl_dir/caCrl.pem # CA certificate revocation list crlnumber = $crl_dir/crlnumber # serial, but for the certificate revocation list crl_extensions = crl_ext # the name of the tag in this file, which specifies certificates revocation list extensions, which will be added to the certificate revocation by default. default_crl_days = 30 # default number of days for which the certificate revocation list will be valid since the date of its generation. After that date it should be updated to see if there are new entries on the list. [ req ] default_bits = 4096 # default key size in bits. distinguished_name = req_distinguished_name # the name of the tag in this file, which specifies certificates fields description during certificate creation and eventually set some default values. string_mask = utf8only # permitted string type mask. default_md = sha256 # hash function. x509_extensions = v3_ca # the name of the tag in this file, which specifies certificates extensions, which will be added to the created certificate by default. # descriptions and default values of the created certificate fields. [ req_distinguished_name ] countryName = Country Name (2 letter code) stateOrProvinceName = State or Province Name localityName = Locality Name organizationName = Organization Name organizationalUnitName = Organizational Unit Name commonName = Common Name emailAddress = Email Address # A default value for each field can be set by adding an extra line with field name and postfix "_default". For example: "countryName_default = PL". If you add this line here, then leaving country name empty during certificate creation will result in the value "PL" being used. If the default value was specified there, but during certificate creation you do not want to use this value, then instead use "." as the value. It will leave the value empty and not use the default. # default extensions for the CA certificate. [ v3_ca ] subjectKeyIdentifier = hash # subject key value will be calculated using hash funtion. It's the recommended setting by PKIX. authorityKeyIdentifier = keyid:always,issuer # The subject key identifier will be copied from the parent certificate. It's the recommended setting by PKIX. basicConstraints = critical, CA:true, pathlen:10 # "critical" specifies that the extension is important and must be read by the platform. CA says if it is the CA certificate so it can be used to sign different certificates. "pathlen" specifies the maximum path length between this certificate and the device certificate in the chain of certificates during authentication. Path length is set here only to show how it is done. If you do not want to specify max path length, you can keep only the "basicConstraints = critical, CA:true" part here. keyUsage = digitalSignature, cRLSign, keyCertSign # specifies permitted key usages. # Default extensions for the device certificate. This tag is not used directly anywhere in this file, but will be used from the command line to create signed certificate with "-extensions v3_signed" parameter. [ v3_signed ] subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer basicConstraints = critical, CA:false keyUsage = nonRepudiation, digitalSignature, keyEncipherment # default extensions for certificate revocation list [ crl_ext ] authorityKeyIdentifier=keyid:always # Policy of certificates signing. It specifies which certificate fields must be filled in during certificate creation. There are three possible values here: # "optional" - field value can be empty # "supplied" - field value must be filled in # "match" - signed certificate field value must match the CA certificate value to be created [ signing_policy ] countryName = optional stateOrProvinceName = optional organizationName = optional organizationalUnitName = optional commonName = supplied # every certificate should have a unique common name, so this value should not be changed. emailAddress = optional
-
暗号化方式が aes256 で、長さが 2,048 ビット以上の秘密鍵を作成します。作成時には鍵のパスワードを設定するよう求められます。
openssl genrsa -aes256 -out caKey.pem 4096
-
構成ファイルの仕様を使用して自己署名証明書を作成します。「days」パラメータは、この証明書が生成されてから有効期限を示すため、お好みに応じて設定してください。
openssl req -config caConfig.cnf -key caKey.pem -new -x509 -days 7300 -sha256 -extensions v3_ca -out caCert.pem
-
次のコマンドを使用して、作成した証明書を印刷できます。
openssl x509 -noout -text -in caCert.pem
中間証明書の作成
中間証明書は CA 証明書によって署名されますが、デバイス証明書の署名にも使用されます。 このステップは任意です。 すべてのデバイス証明書を1つの共通のCA証明書で署名しても問題ない場合は、このステップをスキップできます。 ただし、CA 証明書とデバイス証明書の間にいくつかの証明書が必要な場合は、このステップを実行することが適切です。 Things Cloudクラウドでは、証明書のチェーンの最大長が現在10に制限されていることに注意してください。
この動作は、プラットフォーム全体の構成設定を変更し、証明書チェーンの許容最大長を 10 より長く (または短く) 増やす (または減らす) ことで、専用インストールの場合に変更できます。 長さが 2 を超えるチェーンを使用する場合は、DOS 攻撃からサービスを保護するために所有証明機能を使用することを強くお勧めします。
- caCertificate パス内に中間証明書用の新しいディレクトリを作成します:
mkdir intermediateCertificate
- このディレクトリに移動し、中間証明書の構成ファイルを作成します:
touch intermediateConfig.cnf
- 中間証明書によって署名された証明書の履歴を保持するためのデータベース ファイルを作成します:
touch database.txt
- 署名付き証明書を識別するために使用される、初期シリアル番号を含むシリアルファイルを作成します:
echo 1000 > serial
- 署名付き証明書と証明書失効リスト用のサブディレクトリを作成します:
mkdir deviceCertificates crl
- CA 構成と同じように構成ファイルに記入しますが、一般ディレクトリ (「dir」) をintermediateCertificate フォルダに変更することを忘れないでください。また、private_key、certificates、crlの名前を、現在の「ca」プレフィクスから「intermediate」プレフィクスに変更しなければなりません(例: caKey.pem -> intermediateKey.pem)。次のステップで、このプレフィクスを持つファイルを生成するためです。
- 中間証明書の秘密鍵を生成します:
openssl genrsa -aes256 -out intermediateKey.pem 4096
- 証明書署名リクエストを生成します:
openssl req -config intermediateConfig.cnf -new -sha256 -key intermediateKey.pem -out intermediateCsr.pem
- caCertificate ディレクトリに移動し、署名付き中間証明書を生成します。構成ファイルで指定された秘密鍵が証明書の署名に使用されるため、ここでは CA 構成を使用する必要があります:
openssl ca -config caConfig.cnf -extensions v3_ca -days 3650 -notext -md sha256 -in intermediateCertificate/intermediateCsr.pem -out intermediateCertificate/intermediateCert.pem
- 生成された証明書が CA によって正しく署名されているかどうかを確認します:
openssl verify -CAfile caCert.pem intermediateCertificate/intermediateCert.pem
CAまたは中間認証局によって署名されたデバイス証明書の作成
- デバイス証明書の署名にどちらが使用されているかに応じて、caCertificate またはintermediateCertificate のディレクトリに移動します。
- 新しい証明書の秘密鍵を生成します:
openssl genrsa -aes256 -out deviceCertificates/deviceKey.pem 4096
- 証明書署名リクエストを生成します (intermediateCertificate ディレクトリにいる場合は、「caConfig.cnf」を「intermediateConfig.cnf」に変更します):
openssl req -config caConfig.cnf -new -sha256 -key deviceCertificates/deviceKey.pem -out deviceCertificates/deviceCsr.pem
コンソールで指定するように求められるデバイス証明書のcommonName
は、接続中にデバイスの ClientId と一致する必要があることに注意してください。 - CA または中間認証局によって署名された証明書を生成します (intermediateCertificate ディレクトリにいる場合は、「caConfig.cnf」を「intermediateConfig.cnf」に変更します):
openssl ca -config caConfig.cnf -extensions v3_signed -days 365 -notext -md sha256 -in deviceCertificates/deviceCsr.pem -out deviceCertificates/deviceCert.pem
- 生成された証明書が CA または中間認証局によって正しく署名されているかどうかを確認します (intermediateCertificate ディレクトリにいる場合は、「caCert.pem」を「intermediateCert.pem」に変更します):
openssl verify -partial_chain -CAfile caCert.pem deviceCertificates/deviceCert.pem
証明書チェーンの作成
caCertificate ディレクトリに移動します。
CA 証明書を作成し、それを中間証明書の署名に使用し、中間証明書を使用してデバイス証明書の署名を行った場合は、次のコマンドを使用してチェーンを作成します。
cat intermediateCertificate/deviceCertificates/deviceCert.pem intermediateCertificate/intermediateCert.pem caCert.pem > intermediateCertificate/deviceCertificates/deviceCertChain.pem
中間証明書を使用しない場合のコマンドは次の通りです。
cat deviceCertificates/deviceCert.pem caCert.pem > deviceCertificates/deviceCertChain.pem
CA証明書とデバイス証明書の間に複数の中間証明書を使用する場合、チェーン作成時に正しい順序を保つ必要があることを忘れないでください(すべての証明書の後に、その証明書によって署名されている証明書が続く必要があります)。
キーストアとトラストストアの作成
- デバイスの秘密鍵と生成された証明書のチェーンを使用して、deviceCertificates ディレクトリに移動します。CA証明書とデバイス証明書の間に中間証明書を使用している場合は、
caCertificate/intermediateCertificate/deviceCertificates
がパスになり、それ以外の場合はcaCertificate/deviceCertificates
になります。生成された証明書のチェーンとデバイスの秘密鍵を使用してキーストアを作成します:openssl pkcs12 -export -name devicekeyentry -inkey deviceKey.pem -in deviceCertChain.pem -out deviceKeystore.pkcs12
- キーストアを JKS 形式に変換する場合は、通常 Java Development Kit と一緒にダウンロードされる Java Keytool が必要になります:
keytool -importkeystore -srckeystore deviceKeystore.pkcs12 -srcstoretype PKCS12 -destkeystore deviceKeystore.jks -deststoretype JKS
- サーバー証明書がない場合は、次のコマンドで取得します:
openssl s_client -showcerts -connect <cumulocity url>:<mqtt mutual ssl port (currently 8883, but that can be changed in the future)> | openssl x509 -outform PEM > serverCertificate.pem
- これで、サーバー証明書を格納するトラストストアを作成することができます。これはJava Keytoolで作成する必要があります (opensslはトラストストアの作成をサポートしていないので、Java keytoolを使用しない場合は、すべての信頼できる証明書を別のPEMファイルに保持する必要があります)。
alias
は、すべてのキーストアまたはトラストストア エントリの一意の識別子であることに注意してください。これは、同じトラストストアに 2 番目の信頼できる証明書を追加する場合は、以下のコマンドのエイリアスをservercertificate
から別の名前に変更する必要があることを意味します:- PKCS12 形式の場合:
keytool -importcert -noprompt -keystore deviceTruststore.pkcs12 -alias servercertificate -file serverCertificate.pem
- JKS 形式の場合:
keytool -import -file serverCertificate.pem -alias servercertificate -keystore deviceTruststore.jks
- PKCS12 形式の場合:
- オプションとして、トラストストアの新しいファイルを作成する代わりに、作成したキーストアに信頼できる証明書を追加し、すべてを 1 つのファイルに保存できますが、これは推奨される解決策ではありません:
- キーストアが PKCS12 形式の場合:
keytool -importcert -noprompt -keystore deviceKeystore.pkcs12 -alias servercertificate -file serverCertificate.pem
- キーストアが JKS 形式の場合:
keytool -import -file serverCertificate.pem -alias servercertificate -keystore deviceKeystore.jks
- キーストアが PKCS12 形式の場合:
- 次のコマンドを使用して、キーストア (またはトラストストア) の内容を確認できます:
keytool -list -v -keystore deviceKeystore.jks
キーストアとトラストストア
まだキーストアとトラストストアを生成していない場合は、証明書の生成と署名の説明に従って行います。
CA 証明書のアップロード
CA(または中間)証明書をプラットフォームにアップロードします。この操作により、アップロードされた証明書がサーバーのトラストストアに追加されます。この操作には2つの方法があり、どちらもROLE_TENANT_ADMINまたはROLE_TENANT_MANAGEMENT_ADMINのいずれかのロール要件があります。
UIの場合
- デバイス管理アプリケーションで、ナビゲータの 管理 メニューに移動し、信頼できる証明書 を選択します。
- 表示されるダイアログで、新しい証明書のカスタム名を入力します。
- CA 証明書 (caCert.pem またはintermediateCert.pem) を削除します。
- 自動登録 チェックボックスを選択します。
- トグルを 有効 に設定します。
- 証明書を追加をクリックします。
その後、新しい証明書が信頼できる証明書リストに追加されます:
REST APIの場合
- Things Cloud プラットフォームにアップロードする CA (または中間) 証明書を表示し、その PEM 値をコピーします。この値は、「—–BEGIN CERTIFICATE—–」で始まり、「—–END CERTIFICATE—–」で終わります (ハイフン含む)。改行記号(
\n
)が各行の末尾に自動的に追加された場合は、それを削除します:openssl x509 -in caCert.pem -text
- POSTリクエストを介してプラットフォームに送信します。
POST /tenant/tenants/<TENANT_ID>/trusted-certificates
Host: https://<TENANT_DOMAIN>/
Authorization: Basic <YOUR_AUTHENTICATION>
Content-Type: application/json
{
"status" : "ENABLED",
"name" : "certificateName",
"autoRegistrationEnabled" : "true",
"certInPemFormat" : "<CERT_PEM_VALUE>"
}
所有証明の実行
Things Cloud プラットフォームは、X.509 証明書を使用してエンドデバイスを認証します。 証明書は信頼の連鎖で機能します。信頼できる証明書を使用して、信頼できるサブ証明書を作成できます。 各証明書はパブリック部分とプライベート部分で構成されます。 非対称暗号化 もご覧ください。
Things Cloud プラットフォームは、デバイス認証に使用される各証明書の公開部分を受け取ります。 各証明書は一意に割り当てる必要があるため、テナントへのデバイスの割り当ても証明書によって行われます。 所有証明の手順を実行すると、事前の所有証明のないすべての証明書がフィルタリングされ、検証済みの所有証明を持つ証明書のテナント マッピングが優先されます。
ただし、証明書 (およびサブ証明書) の公開部分は秘密ではないため、理論的にはインターネット上の誰でもアクセスできます。 潜在的な攻撃者は、証明書のプライベート部分にアクセスできない (したがって証明書の所有者ではない) 場合でも、証明書のパブリック部分を Things Cloud プラットフォームにアップロードする可能性があります。 この場合、Things Cloud プラットフォームはどのアップローダーが正規のものであるかを判断できないため、プラットフォームはこの証明書への参照を有効なものとして受け入れず、DOS シナリオが発生します。
アップロード者による所有権の検証を確実にするために、プラットフォームは所有権の証明を必要とします。
所有証明の手順は以下の通りです:
-
デバイス管理アプリケーションで 管理 > 信頼できる証明書 に移動し、証明書が適切にアップロードされていることを確認します。
-
証明書の詳細の 所有証明 セクションで、確認コードをダウンロードします。
-
証明書の秘密キーを使用して検証コードを暗号化し、署名付き検証コードを生成します。 次の OpenSSL コマンドを使用します:
openssl dgst -sha256 -sign <private.key> <verification_code.txt> | openssl base64 -A
-
署名された確認コードをプラットフォームにアップロードします。
アップロードされた署名付き検証コードが、プラットフォームが期待する署名付き検証コードと一致する場合、所有証明が確認されます。 これは、所有証明 セクションで状態を「不完全」から「完了」に切り替えることで示されます。
MQTT クライアント例
x.509 証明書を使用してプラットフォームに接続する、Java で実装された Things Cloud MQTT サンプル クライアントのコードは、ここから入手できます:
https://github.com/SoftwareAG/cumulocity-examples/tree/develop/mqtt-client
このサンプル クライアントでは、Eclipse Paho の実装が使用されています。詳細については、Webサイト(https://www.eclipse.org/paho/index.php?page=documentation.php) で説明されています。
以下は、Eclipse Paho クライアントを使用するために必要な依存関係を Maven に追加する方法を示す例です。
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>${paho.version}</version>
</dependency>
次に、MQTT クライアントのインスタンスを 1 行で作成できます。
MqttClient mqttClient = new MqttClient(BROKER_URL, "d:" + CLIENT_ID, new MemoryPersistence());
BROKER_URL には、ssl://<cumulocity url>:8883
のように、クライアントが接続するプロトコル、URL、ポートが含まれている必要があります。
CLIENT_ID 値は、使用されるデバイス証明書のコモンネームの値と一致する必要があります。
「d:」プレフィクスは、デバイス接続のために Things Cloud で使用されているため、削除または変更しないでください。
SSL 接続を確立するために設定する必要があるのは、コードフラグメントにパスを入力することだけです。
sslProperties.put(SSLSocketFactoryFactory.KEYSTORE, getClass().getClassLoader().getResource(KEYSTORE_NAME).getPath());
sslProperties.put(SSLSocketFactoryFactory.KEYSTOREPWD, KEYSTORE_PASSWORD);
sslProperties.put(SSLSocketFactoryFactory.KEYSTORETYPE, KEYSTORE_FORMAT);
sslProperties.put(SSLSocketFactoryFactory.TRUSTSTORE, getClass().getClassLoader().getResource(TRUSTSTORE_NAME).getPath());
sslProperties.put(SSLSocketFactoryFactory.TRUSTSTOREPWD, TRUSTSTORE_PASSWORD);
sslProperties.put(SSLSocketFactoryFactory.TRUSTSTORETYPE, TRUSTSTORE_FORMAT);
- KEYSTORE_NAME は、キーストアへのパスです。キーストアには、デバイス自体を認証するために使用する秘密鍵と証明書のチェーンが含まれています。
- KEYSTORE_PASSWORD は、キーストアがその秘密鍵を使用するために作成されたパスワードです。
- KEYSTORE_FORMATはファイル形式に応じて「JKS」または「PKCS12」にする必要があります。 パスは KEYSTORE_NAME によって提供されます。
- TRUSTSTORE_NAME は、サーバーの証明書が含まれるトラストストアへのパスです。
- TRUSTSTORE_PASSWORD はトラストストアにアクセスするためのパスワードです。
- TRUSTSTORE_FORMAT は、ファイル形式に応じて「JKS」または「PKCS12」にする必要があります。 パスは TRUSTSTORE によって提供されます。
このデータを入力すると、サンプルクライアントは提供されたデータを使用し、証明書を用いて指定されたプラットフォームに接続します。
この例では、接続用のコールバックを作成する方法も示しています。
まず最初に、インターフェース MqttCallbackExtended
を実装するクラスを作成します。
次に、このようなクラスを作成し、そのインスタンスを MQTT クライアントに提供できます: mqttClient.setCallback(this);
一般的に、MQTT Eclipse Paho クライアントは Java Development Kit の一部である Java Secure Socket Extension を使用して SSL によるセキュアな接続を提供します。 JSSE は、開発者がそのクラスを使用して構成できる SSL および TLS プロトコルの Java 実装を提供します。 Java Secure Socket Extension のドキュメントでは、SSL 接続がどのように確立されるかを示し、実装をカスタマイズする例をいくつか提供しています。 完全なドキュメントは、Oracle 公式 Webサイト で入手できます。