XML ドキュメントの暗号化
このトピックでは、XML ドキュメントを暗号化する方法を説明します。
このネームスペースで SOAP ロギングを有効にしておくと、エラーの詳細を受信するので便利です。"InterSystems IRIS での SOAP の問題のトラブルシューティング" の "InterSystems IRIS SOAP ログ" を参照してください。
暗号化された XML ドキュメントについて
暗号化された XML ドキュメントには以下の要素が含まれます。
-
<EncryptedData> 要素。ここには、ランダムに生成された対称鍵によって暗号化されたデータが含まれます (公開鍵よりも対称鍵を使用した方が、暗号化の効率はアップします)。
-
1 つ以上の <EncryptedKey> 要素。それぞれの <EncryptedKey> 要素には、データの暗号化に使用された対称鍵を暗号化したコピーが保持されています。また、公開鍵を使用した X.509 証明書も含まれています。一致する秘密鍵を持っている受信者は、対称鍵を解読してから <EncryptedData> 要素を解読できます。
-
(オプション) クリア・テキストによる他の要素
以下に例を示します。
<?xml version="1.0" encoding="UTF-8"?>
<Container xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptedKey>
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p">
<DigestMethod xmlns="http://www.w3.org/2000/09/xmldsig#"
Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
</EncryptionMethod>
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>MIICnDCCAYQCAWUwDQYJKo... content omitted</X509Certificate>
</X509Data>
</KeyInfo>
<CipherData>
<CipherValue>J2DjVgcB8vQx3UCy5uejMB ... content omitted</CipherValue>
</CipherData>
<ReferenceList>
<DataReference URI="#Enc-E0624AEA-9598-4436-A154-F746B07A2C55"></DataReference>
</ReferenceList>
</EncryptedKey>
<EncryptedData Id="Enc-E0624AEA-9598-4436-A154-F746B07A2C55"
Type="http://www.w3.org/2001/04/xmlenc#Content">
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc">
</EncryptionMethod>
<CipherData>
<CipherValue>LmoBK7+nDelTOsC3 ... content omitted</CipherValue>
</CipherData>
</EncryptedData>
</Container>
暗号化されたドキュメントを作成するには、クラス %XML.Security.EncryptedDataOpens in a new tab および %XML.Security.EncryptedKeyOpens in a new tab を使用します。これら XML 対応のクラスは、適切なネームスペースにある有効な <EncryptedData> 要素と <EncryptedKey> に投影されます。
暗号化された XML ドキュメントの作成
暗号化された XML ドキュメントを作成する最も簡単な方法は、以下のとおりです。
-
目的の XML ドキュメントに直接投影できる汎用コンテナ・クラスを定義して使用します。
-
暗号化する XML を格納したストリームを作成します。
-
対応する暗号化キーと共に、そのストリームを暗号化して、コンテナ・クラスの適切なプロパティに書き込みます。
-
コンテナ・クラスの XML 出力を生成します。
暗号化の前提条件
ドキュメントを暗号化するには、まず暗号化されたドキュメントの送信先となるエンティティの証明書を含む InterSystems IRIS® データ・プラットフォーム資格情報セットを作成する必要があります。この場合、関連付けられている秘密鍵は必要はありません (また、持つべきではありません)。詳細は、"設定およびその他の一般的なアクティビティ" を参照してください。
コンテナ・クラスの要件
汎用コンテナ・クラスには、以下のものが含まれている必要があります。
-
タイプが %XML.Security.EncryptedDataOpens in a new tab で、<EncryptedData> 要素として投影されているプロパティ。
このプロパティには、暗号化されたデータが保持されます。
-
タイプが %XML.Security.EncryptedKeyOpens in a new tab で、<EncryptedKey> 要素として投影されている、少なくとも 1 つのプロパティ。
これらのプロパティには、対応するキーの情報が保持されます。
以下に例を示します。
Class XMLEncryption.Container Extends (%RegisteredObject, %XML.Adaptor)
{
Property Data As %XML.Security.EncryptedData (XMLNAME="EncryptedData");
Property Key As %XML.Security.EncryptedKey (XMLNAME="EncryptedKey");
Parameter NAMESPACE = "http://www.w3.org/2001/04/xmlenc#";
//methods
}
暗号化された XML ドキュメントの生成
暗号化されたドキュメントを生成して記述する手順は次のとおりです。
-
XML ドキュメントを格納したストリームを作成します。
このためには通常、%XML.WriterOpens in a new tab を使用して、XML 対応オブジェクトの出力をストリームに書き込みます。
-
暗号化されたドキュメントの送信先となるエンティティの InterSystems IRIS 資格情報セットにアクセスする %SYS.X509CredentialsOpens in a new tab のインスタンスを少なくとも 1 つ作成します。これには、このクラスの GetByAlias() クラス・メソッドを呼び出します。以下はその例です。
set credset=##class(%SYS.X509Credentials).GetByAlias("recipient")
このメソッドを実行するには、当該の資格情報セットの OwnerList に記載されたユーザとしてログインするか、OwnerList が NULL である必要があります。"プログラムによる資格情報セットの取得" も参照してください。
-
%XML.Security.EncryptedKeyOpens in a new tab のインスタンスを少なくとも 1 つ作成します。このクラスのインスタンスを作成するには、このクラスの CreateX509() クラス・メソッドを使用します。以下はその例です。
set enckey=##class(%XML.Security.EncryptedKey).Createx509(credset,encryptionOptions,referenceOption)
-
credset は、先ほど作成した %SYS.X509CredentialsOpens in a new tab のインスタンスです。
-
encryptionOptions は $$$SOAPWSIncludeNone です (他のオプションもありますが、このシナリオには該当しません)。
このマクロは、%soap.inc インクルード・ファイルで定義されているマクロです。
-
referenceOption は、暗号化された要素に対する参照の特性です。許可される値については、"X.509 証明書の参照オプション" を参照してください。
ここで使用されるマクロは、%soap.inc インクルード・ファイルで定義します。
-
-
%Library.ListOfObjectsOpens in a new tab のインスタンスを作成し、その Insert() メソッドを使用して、先ほど作成した %XML.Security.EncryptedKeyOpens in a new tab のインスタンスを挿入します。
-
%New() メソッドを使用して、%XML.Security.EncryptedDataOpens in a new tab のインスタンスを作成します。以下はその例です。
set encdata=##class(%XML.Security.EncryptedData).%New()
-
%XML.Security.EncryptedDataOpens in a new tab の EncryptStream() インスタンス・メソッドを使用して、手順 2 で作成したストリームを暗号化します。例えば、以下のようになります。
set status=encdata.EncryptStream(stream,encryptedKeys)
-
stream は、手順 1 で作成したストリームです。
-
encryptedKeys は、手順 4 で作成したキーのリストです。
-
-
コンテナ・クラスのインスタンスを作成して更新します。
-
キーのリストを、このクラスの適切なプロパティに書き込みます。
-
%XML.Security.EncryptedDataOpens in a new tab のインスタンスを、このクラスの適切なプロパティに書き込みます。
この詳細は、クラスによって異なります。
-
-
%XML.WriterOpens in a new tab を使用して、コンテナ・クラスの出力を生成します。"オブジェクトからの XML 出力の記述" を参照してください。
例えば、前に示したコンテナ・クラスには以下のメソッドも含まれます。
ClassMethod Demo(filename = "",obj="")
{
#include %soap
if (obj="") {
set obj=##class(XMLEncryption.Person).GetPerson()
}
//create stream from this XML-enabled object
set writer=##class(%XML.Writer).%New()
set stream=##class(%GlobalCharacterStream).%New()
set status=writer.OutputToStream(stream)
if $$$ISERR(status) {do $System.Status.DisplayError(status) quit }
set status=writer.RootObject(obj)
if $$$ISERR(status) {do $System.Status.DisplayError(status) quit }
do stream.Rewind()
set container=..%New() ; this is the object we will write out
set cred=##class(%SYS.X509Credentials).GetByAlias("servercred")
set parts=$$$SOAPWSIncludeNone
set ref=$$$KeyInfoX509Certificate
set key=##class(%XML.Security.EncryptedKey).CreateX509(cred,parts,ref)
set container.Key=key ; this detail depends on the class
//need to create a list of keys (just one in this example)
set keys=##class(%Collection.ListOfObj).%New()
do keys.Insert(key)
set encdata=##class(%XML.Security.EncryptedData).%New()
set status=encdata.EncryptStream(stream,keys)
set container.Data=encdata ; this detail depends on the class
// write output for the container
set writer=##class(%XML.Writer).%New()
set writer.Indent=1
if (filename'="") {
set status=writer.OutputToFile(filename)
if $$$ISERR(status) {do $system.OBJ.DisplayError(status) quit}
}
set status=writer.RootObject(container)
if $$$ISERR(status) {do $system.OBJ.DisplayError(status) quit}
}
このメソッドは、任意の XML 対応クラスの OREF を受け入れることができます。何も提供されていない場合は、既定値が使用されます。
暗号化された XML ファイルの解読
解読の前提条件
暗号化された XML ドキュメントを解読するには、まず以下の両方を用意する必要があります。
-
InterSystems IRIS が使用するための信頼された証明書。
-
暗号化で使用されている公開鍵と秘密鍵が一致している InterSystems IRIS 資格情報セット。
詳細は、"設定およびその他の一般的なアクティビティ" を参照してください。
ドキュメントの解読
暗号化された XML ドキュメントを解読する手順は次のとおりです。
-
%XML.ReaderOpens in a new tab のインスタンスを作成し、それを使用してドキュメントを開きます。
"オブジェクトへの XML のインポート" を参照してください。
-
リーダの Document プロパティを取得します。これは、XML ドキュメントを DOM として含む %XML.DocumentOpens in a new tab のインスタンスです。
-
リーダの Correlate() メソッドを使用して、1 つまたは複数の <EncryptedKey> 要素をクラス %XML.Security.EncryptedKeyOpens in a new tab に関連付けます。以下はその例です。
do reader.Correlate("EncryptedKey","%XML.Security.EncryptedKey")
-
ドキュメントで 1 つまたは複数の <EncryptedKey> 要素を繰り返し読み取ります。このためには、インポートされたオブジェクトがあれば参照によって返す、リーダの Next() メソッドを使用します。以下はその例です。
if 'reader.Next(.ikey,.status) { write !,"Unable to import key",! do $system.OBJ.DisplayError(status) quit }
インポートされたオブジェクトは %XML.Security.EncryptedKeyOpens in a new tab のインスタンスです。
-
%Library.ListOfObjectsOpens in a new tab のインスタンスを作成し、その Insert() メソッドを使用して、ドキュメントから先ほど取得した %XML.Security.EncryptedKeyOpens in a new tab のインスタンスを挿入します。
-
クラス %XML.Security.EncryptedDataOpens in a new tab の ValidateDocument() メソッドを呼び出します。
set status=##class(%XML.Security.EncryptedData).ValidateDocument(.doc,keys)
参照によって返される最初の引数は、手順 2 で取得した DOM を変更したものです。2 番目の引数は、前の手順からのキーのリストです。
-
必要に応じて、%XML.WriterOpens in a new tab を使用して、変更された DOM の出力を生成します。"オブジェクトからの XML 出力の記述" を参照してください。
次に、例を示します。
ClassMethod DecryptDoc(filename As %String)
{
#include %soap
set reader=##class(%XML.Reader).%New()
set status=reader.OpenFile(filename)
if $$$ISERR(status) {do $System.Status.DisplayError(status) quit }
set doc=reader.Document
//get <Signature> element
do reader.Correlate("EncryptedKey","%XML.Security.EncryptedKey")
if 'reader.Next(.ikey,.status) {
write !,"unable to import key",!
do $system.OBJ.DisplayError(status)
quit
}
set keys=##class(%Collection.ListOfObj).%New()
do keys.Insert(ikey)
// the following step returns the decrypted document
set status=##class(%XML.Security.EncryptedData).ValidateDocument(.doc,keys)
set writer=##class(%XML.Writer).%New()
set writer.Indent=1
do writer.Document(doc)
quit $$$OK
}