서명된 데이터가 서명 자체와 동일한 문서에 있는 경우 참조의 URI는 일반적으로 XPath 또는 XPointer 구문을 사용하여 서명된 요소를 처리합니다. XML 서명 구문 및 처리를 위한 W3C 권장 사항에서는 이 구문만 권장하므로 발견할 수 있는 서명을 기반으로 구현하고 지원되지 않는 구문을 적절히 처리할 수 있는 오류 확인을 추가해야 합니다.
AIR 응용 프로그램의 서명은 엔벌로프 중인 서명의 예입니다. 응용 프로그램의 파일은 Manifest 요소에 나열됩니다. Manifest 요소는 Manifest 요소의 ID를 나타내는 “#PackageContents” 문자열을 사용하여 Reference URI 특성에서 처리합니다.
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#" Id="PackageSignature">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
<SignatureMethod Algorithm="http://www.w3.org/TR/xmldsig-core#rsa-sha1"/>
<Reference URI="#PackageContents">
<Transforms>
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<DigestValue>ZMGqQdaRKQc1HirIRsDpeBDlaElS+pPotdziIAyAYDk=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue Id="PackageSignatureValue">cQK...7Zg==</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>MII...T4e</X509Certificate>
</X509Data>
</KeyInfo>
<Object>
<Manifest Id="PackageContents">
<Reference URI="mimetype">
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256">
</DigestMethod>
<DigestValue>0/oCb84THKMagtI0Dy0KogEu92TegdesqRr/clXct1c=</DigestValue>
</Reference>
<Reference URI="META-INF/AIR/application.xml">
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256">
</DigestMethod>
<DigestValue>P9MqtqSdqcqnFgeoHCJysLQu4PmbUW2JdAnc1WLq8h4=</DigestValue>
</Reference>
<Reference URI="XMLSignatureValidation.swf">
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256">
</DigestMethod>
<DigestValue>OliRHRAgc9qt3Dk0m0Bi53Ur5ur3fAweIFwju74rFgE=</DigestValue>
</Reference>
</Manifest>
</Object>
</Signature>
이 서명의 유효성을 검사하는 데 사용되는 역참조자는 Reference 요소의
"#PackageContents"
를 포함하는 URI 문자열을 사용하고 ByteArray 객체의 Manifest 요소를 반환해야 합니다. “#” 심볼은 요소 ID 특성의 값을 나타냅니다.
다음 예제에서는 AIR 응용 프로그램 서명의 유효성을 검사하는 데 사용되는 역참조자를 구현합니다. 구현은 AIR 서명의 알려진 구조를 이용하여 간단하게 유지됩니다. 일반적인 용도의 역참조자는 매우 복잡할 수 있습니다.
package
{
import flash.events.ErrorEvent;
import flash.security.IURIDereferencer;
import flash.utils.ByteArray;
import flash.utils.IDataInput;
public class AIRSignatureDereferencer implements IURIDereferencer {
private const XML_SIG_NS:Namespace =
new Namespace( "http://www.w3.org/2000/09/xmldsig#" );
private var airSignature:XML;
public function AIRSignatureDereferencer( airSignature:XML ) {
this.airSignature = airSignature;
}
public function dereference( uri:String ):IDataInput {
var data:ByteArray = null;
try
{
if( uri != "#PackageContents" )
{
throw( new Error("Unsupported signature type.") );
}
var manifest:XMLList =
airSignature.XML_SIG_NS::Object.XML_SIG_NS::Manifest;
data = new ByteArray();
data.writeUTFBytes( manifest.toXMLString());
data.position = 0;
}
catch (e:Error)
{
data = null;
throw new Error("Reference not resolvable: " + uri + ", " + e.message);
}
finally
{
return data;
}
}
}
}
이러한 유형의 서명을 확인할 때 Manifest 요소에 있는 데이터의 유효성만 검사합니다. 패키지의 실제 파일은 확인하지 않습니다. 패키지 파일의 변경 여부를 확인하려면 파일을 읽고, SHA256 다이제스트를 계산하고, 결과를 목록에 기록된 다이제스트와 비교해야 합니다. XMLSignatureValidator는 이러한 2차 참조를 자동으로 확인하지 않습니다.
참고:
이 예제는 서명 유효성 검사 프로세스를 보여 주기 위해서만 제공됩니다. 자체 서명의 유효성을 검사하기 위해 AIR 응용 프로그램에서 사용되는 경우는 거의 없습니다. 응용 프로그램이 이미 변경된 경우 변경하는 에이전트는 단순히 유효성 검사 확인을 제거할 수 있습니다.
외부 리소스에 대한 다이제스트 값 계산
AIR에는 SHA256 다이제스트 계산을 위한 내장 함수가 없지만 Flex SDK에는 SHA256 유틸리티 클래스가 있습니다. SDK는 계산된 다이제스트를 서명에 저장된 다이제스트와 비교하는 데 유용한 Base64 인코더 유틸리티 클래스도 포함할 수 있습니다.
다음 예제 함수에서는 AIR 패키지 목록의 파일을 읽고 유효성을 검사합니다.
import mx.utils.Base64Encoder;
import mx.utils.SHA256;
private function verifyManifest( sigFile:File, manifest:XML ):Boolean
{
var result:Boolean = true;
var message:String = '';
var nameSpace:Namespace = manifest.namespace();
if( manifest.nameSpace::Reference.length() <= 0 )
{
result = false;
message = "Nothing to validate.";
}
for each (var reference:XML in manifest.nameSpace::Reference)
{
var file:File = sigFile.parent.parent.resolvePath( reference.@URI );
var stream:FileStream = new FileStream();
stream.open(file, FileMode.READ);
var fileData:ByteArray = new ByteArray();
stream.readBytes( fileData, 0, stream.bytesAvailable );
var digestHex:String = SHA256.computeDigest( fileData );
//Convert hexidecimal string to byte array
var digest:ByteArray = new ByteArray();
for( var c:int = 0; c < digestHex.length; c += 2 ){
var byteChar:String = digestHex.charAt(c) + digestHex.charAt(c+1);
digest.writeByte( parseInt( byteChar, 16 ));
}
digest.position = 0;
var base64Encoder:Base64Encoder = new Base64Encoder();
base64Encoder.insertNewLines = false;
base64Encoder.encodeBytes( digest, 0, digest.bytesAvailable );
var digestBase64:String = base64Encoder.toString();
if( digestBase64 == reference.nameSpace::DigestValue )
{
result = result && true;
message += " " + reference.@URI + " verified.\n";
}
else
{
result = false;
message += " ---- " + reference.@URI + " has been modified!\n";
}
base64Encoder.reset();
}
trace( message );
return result;
}
이 함수는 Manifest 요소에 있는 모든 참조를 반복 탐색합니다. 각 참조에 대해 SHA256 다이제스트가 계산되고, base64 형식으로 인코딩되고, 목록의 다이제스트와 비교됩니다. AIR 패키지의 URI는 응용 프로그램 디렉토리에 상대적인 경로를 나타냅니다. 경로는 응용 프로그램 디렉토리 내의 META-INF 하위 디렉토리에 항상 있는 서명 파일의 위치를 기반으로 확인됩니다. Flex SHA256 클래스는 다이제스트를 16진수 문자의 문자열로 반환합니다. 이 문자열은 16진수 문자열이 나타내는 바이트를 포함하는 ByteArray로 변환되어야 합니다.
Flash CS4에서 mx.utils.SHA256 및 Base64Encoder 클래스를 사용하려면 이러한 클래스를 찾아서 응용 프로그램 개발 디렉토리에 복사하거나 Flex SDK를 사용하여 이 클래스를 포함하는 라이브러리 SWF를 컴파일합니다.