Spec-Zone .ru
спецификации, руководства, описания, API
|
Проверка допустимости XML-подписи
Инстанцирование Документа, который Содержит Подпись
Определение Элемента Подписи, который будет Проверен
Создание Контекста Проверки допустимости
Проверка допустимости XML-подписи
Что, Если XML-подпись Не в состоянии Проверить?
Инстанцирование Документа, который будет Подписан
Создание Пары С открытым ключом
Печать или Отображение Получающегося Документа
XML Java API Цифровой подписи является стандартным API Java для генерирования и проверки допустимости XML-подписей. Этот API был определен при Процессе Сообщества Java как JSR 105 (см.
). Этот JSR является заключительным и этот выпуск Java, SE содержит реализацию доступа FCS Окончательной версии API.
XML-подписи могут быть применены к данным любого типа, XML или двоичного файла (см.
). Получающаяся подпись представляется в XML. XML-подпись может использоваться, чтобы защитить Ваши данные и обеспечить целостность данных, аутентификацию сообщений, и аутентификацию подписывающего лица.
После обеспечения краткого обзора XML-подписей и XML API Цифровой подписи, этот документ представляет два примера, которые демонстрируют, как использовать API, чтобы проверить и генерировать XML-подпись. Этот документ предполагает, что у Вас есть элементарные знания криптографии и цифровых подписей.
API разрабатывается, чтобы поддерживать все необходимые или рекомендуемые функции Рекомендации W3C для Синтаксиса XML-подписи и Обработки. API является расширяемым и сменным и является основанным на Архитектуре Поставщика услуг Криптографии Java. API разрабатывается для двух типов разработчиков:
JCA provider
Before getting into specifics, it is important to see how XWS-Security and XML Digital Signature API are related. In this release of the Java SE, XWS-Security is based on non-standard XML Digital Signature APIs.
Java applications and middleware that need to create or process XML Signatures should use this XML Digital Signature API.
It can be used by Web Services Security (the goal for a future release) and by non-Web Services technologies (for example, signing documents stored or transferred in XML). Both JSR 105 and JSR 106 (XML Digital Encryption APIs) are core-XML security components. (See
for more information about JSR 106.)
XWS-Security does not currently use the XML Digital Signature API or XML Digital Encryption APIs. XWS-Security uses the Apache libraries for XML-DSig and XML-Enc. The goal of XWS-Security is to move toward using these APIs in future releases.
--> -->
Эти шесть упомянутых ниже пакетов включают XML API Цифровой подписи:
javax.xml.crypto
пакет содержит общие классы, которые используются, чтобы выполнить XML криптографические операции, такие как генерирование XML-подписи или шифрование данных XML. Два известных класса в этом пакете KeySelector
класс, который позволяет разработчикам предоставлять реализации, которые определяют местоположение и дополнительно проверяют ключей, используя информацию, содержавшуюся в a KeyInfo
объект, и URIDereferencer
класс, который позволяет разработчикам создавать и определять свои собственные реализации разыменования URI.
javax.xml.crypto.dsig
пакет включает интерфейсы, которые представляют базовые элементы, определенные в спецификации цифровой подписи XML W3C. Из основного значения XMLSignature
класс, который позволяет Вам подписывать и проверять цифровой подписи XML. Большинство структур XML-подписи или элементов представляются соответствующим интерфейсом (за исключением KeyInfo
структуры, которые включаются в их собственный пакет и обсуждаются в следующем абзаце). Эти интерфейсы включают: SignedInfo
, CanonicalizationMethod
, SignatureMethod
, Reference
, Transform
, DigestMethod
, XMLObject
, Manifest
, SignatureProperty
, и SignatureProperties
. XMLSignatureFactory
класс является абстрактной фабрикой, которая используется, чтобы создать объекты, которые реализуют эти интерфейсы.
javax.xml.crypto.dsig.keyinfo
пакет содержит интерфейсы, которые представляют большинство KeyInfo
структуры, определенные в рекомендации цифровой подписи XML W3C, включая KeyInfo
, KeyName
, KeyValue
, X509Data
, X509IssuerSerial
, RetrievalMethod
, и PGPData
. KeyInfoFactory
класс является абстрактной фабрикой, которая используется, чтобы создать объекты, которые реализуют эти интерфейсы.
javax.xml.crypto.dsig.spec
пакет содержит интерфейсы, и классы, представляющие входные параметры для обзора, подписи, преобразовывают, или алгоритмы канонизации, используемые в обработке XML-подписей.
Наконец, javax.xml.crypto.dom
и javax.xml.crypto.dsig.dom
пакеты содержат DOM-специфичные классы для javax.xml.crypto
и javax.xml.crypto.dsig
пакеты, соответственно. Только разработчики и пользователи, которые создают или используют DOM-на-основе XMLSignatureFactory
или KeyInfoFactory
реализация должна будет сделать прямое использование этих пакетов.
JSR 105 криптографических служб является конкретной реализацией краткого обзора XMLSignatureFactory
и KeyInfoFactory
классы и ответственны за создание объектов и алгоритмов, которые анализируют, генерируют и проверяют XML-подписей и KeyInfo
структуры. Конкретная реализация XMLSignatureFactory
должен оказать поддержку для каждого из необходимых алгоритмов как определено рекомендацией W3C для XML-подписей. Это может дополнительно поддерживать другие алгоритмы как определено рекомендацией W3C или другие спецификации.
JSR 105 рычагов модель провайдера JCA для регистрации и загрузки XMLSignatureFactory
и KeyInfoFactory
реализации.
Каждый бетон XMLSignatureFactory
или KeyInfoFactory
реализация поддерживает определенный тип механизма XML, который идентифицирует XML, обрабатывающий механизм, который реализация использует внутренне, чтобы проанализировать и генерировать XML-подпись и KeyInfo
структуры. Этот JSR поддерживает один стандартный тип, ДОМА. XML реализация провайдера Цифровой подписи, которая связывается Java SE, поддерживает механизм ДОМА. Поддержка новых стандартных типов, таких как JDOM, может быть добавлена в будущем.
XML реализация API Цифровой подписи должен использовать базовые классы механизма JCA, такой как java.security.Signature
и java.security.MessageDigest
, выполнять криптографические операции.
В дополнение к XMLSignatureFactory
и KeyInfoFactory
классы, JSR 105 поддерживает интерфейс поставщика услуг для алгоритмов канонизации и преобразования. TransformService
класс позволяет Вам разрабатывать и включать реализацию определенного преобразования или алгоритма канонизации для определенного типа механизма XML. TransformService
класс использует стандартную модель провайдера JCA для регистрации и загрузки реализаций. Каждый JSR 105 реализаций должен использовать TransformService
класс, чтобы найти провайдера, который поддерживает, преобразовывает и алгоритмы канонизации в XML-подписи, которые он генерирует или проверяет.
Можно использовать XML-подпись, чтобы подписать любые произвольные данные, является ли это XML или двоичным файлом. Данные идентифицируются через URI в одном или Более опорных элементах. XML-подписи описываются в один или больше из трех форм: отсоединенный, окутывание, или окутанный. Отсоединенная подпись по данным, которые являются внешними, или за пределами элемента подписи непосредственно. Окутывающие подписи являются подписями по данным, которые являются в элементе подписи, и окутанная подпись является подписью, которая содержится в данных, которые это подписывает.
Самый легкий способ описать содержание XML-подписи состоит в том, чтобы показать фактическую выборку и описать каждый компонент более подробно. Следующее является примером окутанной XML-подписи, сгенерированной по содержанию XML-документа. Содержание документа прежде, чем это будет подписано:
Получающаяся окутанная XML-подпись, расположенная с отступом и отформатированная для удобочитаемости, следующие:
<?xml version="1.0" encoding="UTF-8"?> <Envelope xmlns="urn:envelope"> <Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> <SignedInfo> <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/> <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1"/> <Reference URI=""> <Transforms> <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> </Transforms> <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> <DigestValue>uooqbWYa5VCqcJCbuymBKqm17vY=</DigestValue> </Reference> </SignedInfo> <SignatureValue> KedJuTob5gtvYx9qM3k3gm7kbLBwVbEQRl26S2tmXjqNND7MRGtoew== </SignatureValue> <KeyInfo> <KeyValue> <DSAKeyValue> <P> /KaCzo4Syrom78z3EQ5SbbB4sF7ey80etKII864WF64B81uRpH5t9jQTxe Eu0ImbzRMqzVDZkVG9xD7nN1kuFw== </P> <Q>li7dzDacuo67Jg7mtqEm2TRuOMU=</Q> <G> Z4Rxsnqc9E7pGknFFH2xqaryRPBaQ01khpMdLRQnG541Awtx/ XPaF5Bpsy4pNWMOHCBiNU0NogpsQW5QvnlMpA== </G> <Y> qV38IqrWJG0V/mZQvRVi1OHw9Zj84nDC4jO8P0axi1gb6d+475yhMjSc/ BrIVC58W3ydbkK+Ri4OKbaRZlYeRA== </Y> </DSAKeyValue> </KeyValue> </KeyInfo> </Signature> </Envelope>
Signature
элемент был вставлен в контенте, который он подписывает, таким образом делая это окутанная подпись. Необходимое SignedInfo
элемент содержит информацию, которая фактически подписывается:
<SignedInfo> <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/> <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1"/> <Reference URI=""> <Transforms> <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> </Transforms> <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> <DigestValue>uooqbWYa5VCqcJCbuymBKqm17vY=</DigestValue> </Reference> </SignedInfo>
Необходимое CanonicalizationMethod
элемент определяет алгоритм, используемый, чтобы канонизировать SignedInfo
элемент прежде, чем это будет подписано или проверено. Канонизация является процессом преобразования контента XML к канонической форме, чтобы принять во внимание изменения, которые могут лишить законной силы подпись по тем данным. Канонизация необходима из-за природы XML и способа, которым это анализируется различными процессорами и посредниками, которые могут изменить данные так, что, подпись больше не действительна, но данные со знаком все еще логически эквивалентны.
Необходимое SignatureMethod
элемент определяет алгоритм цифровой подписи, используемый, чтобы генерировать подпись, в этом случае DSA с SHA 1.
Один или больше Reference
элементы идентифицируют данные, которые перевариваются. Каждый Reference
элемент идентифицирует данные через URI. В этом примере значение URI является пустой Строкой (""), который указывает на корень документа. Дополнительное Transforms
элемент содержит список один или больше Transform
элементы, каждый из которых описывает алгоритм преобразования, используемый, чтобы преобразовать данные прежде, чем это будет переварено. В этом примере есть тот Transform
элемент для окутанного алгоритма преобразования. Окутанное преобразование требуется для окутанных подписей так, чтобы элемент самой подписи был удален прежде, чем вычислить значение подписи. Необходимое DigestMethod
элемент определяет алгоритм, используемый, чтобы переварить данные, в этом случае SHA1. Наконец необходимое DigestValue
элемент содержит фактическое base64-закодированное переваренное значение.
Необходимое SignatureValue
элемент содержит base64-закодированное значение подписи подписи по SignedInfo
элемент.
Дополнительное KeyInfo
элемент содержит информацию о ключе, который необходим, чтобы проверить подписи:
<KeyInfo> <KeyValue> <DSAKeyValue> <P> /KaCzo4Syrom78z3EQ5SbbB4sF7ey80etKII864WF64B81uRpH5t9jQTxe Eu0ImbzRMqzVDZkVG9xD7nN1kuFw== </P> <Q>li7dzDacuo67Jg7mtqEm2TRuOMU=</Q> <G> Z4Rxsnqc9E7pGknFFH2xqaryRPBaQ01khpMdLRQnG541Awtx/ XPaF5Bpsy4pNWMOHCBiNU0NogpsQW5QvnlMpA== </G> <Y> qV38IqrWJG0V/mZQvRVi1OHw9Zj84nDC4jO8P0axi1gb6d+475yhMjSc/ BrIVC58W3ydbkK+Ri4OKbaRZlYeRA== </Y> </DSAKeyValue> </KeyValue> </KeyInfo>
Это KeyInfo
элемент содержит a KeyValue
элемент, который поочередно содержит a DSAKeyValue
элемент, состоящий из открытого ключа, должен был проверить подписи. KeyInfo
может содержать различный контент, такой как сертификаты X.509 и идентификаторы ключа PGP. См.
из Рекомендации XML-подписи для получения дополнительной информации о различном KeyInfo
типы.
Следующие разделы описывают два примера, которые показывают, как использовать XML API Цифровой подписи:
Можно счесть код показанным в этом разделе в Validate.java
файл в docs/technotes/guides/security/xmldsig
каталог. Файл, на котором это работает, envelopedSignature.xml
, находится в том же самом каталоге.
Чтобы скомпилировать и выполнить пример, выполните следующие команды от docs/technotes/guides/security/xmldsig
каталог:
$ javac Validate.java
$ java Validate signature.xml
signature.xml
в текущем рабочем каталоге.
Этот пример показывает Вам, как проверить XML-подписи, используя JSR 105 API. Пример использует ДОМА (Объектная модель документа), чтобы проанализировать XML-документ, содержащий элемент Подписи и JSR 105 реализаций ДОМА, чтобы проверить подписи.
Сначала мы используем JAXP DocumentBuilderFactory
проанализировать XML-документ, содержащий Подпись. Приложение получает реализацию по умолчанию для DocumentBuilderFactory
вызывая следующую строку кода:
Мы должны также сделать фабрику осведомленной о пространстве имен:
Затем, мы используем фабрику, чтобы получить экземпляр a DocumentBuilder
, который используется, чтобы проанализировать документ:
DocumentBuilder builder = dbf.newDocumentBuilder(); Document doc = builder.parse(new FileInputStream(argv[0]));
Мы должны определить Signature
элемент, которого мы хотим проверить, с тех пор в документе мог быть больше чем один. Мы используем метод ДОМА Document.getElementsByTagNameNS
, передача этого URI пространства имен XML Signature и имя тега Signature
элемент, как показано:
NodeList nl = doc.getElementsByTagNameNS (XMLSignature.XMLNS, "Signature"); if (nl.getLength() == 0) { throw new Exception("Cannot find Signature element"); }
Это возвращает список всех Signature
элементы в документе. В этом примере есть только один Signature
элемент.
Мы создаем XMLValidateContext
экземпляр, содержащий входные параметры для того, чтобы проверить подписи. Так как мы используем ДОМА, мы инстанцируем a DOMValidateContext
экземпляр (подкласс XMLValidateContext
), и передача это два параметра, a KeyValueKeySelector
возразите и ссылка на Signature
элемент, который будет проверен (который является первой записью NodeList
мы генерировали ранее):
KeyValueKeySelector
объясняется более подробно в Использовании KeySelectors.
Мы извлекаем содержание Signature
элемент в XMLSignature
объект. Этот процесс вызывают, неупорядочивая. Signature
элемент неупорядочивается, используя XMLSignatureFactory
объект. Приложение может получить реализацию ДОМА XMLSignatureFactory
вызывая следующую строку кода:
Мы тогда вызываем unmarshalXMLSignature
метод фабрики, чтобы неупорядочить XMLSignature
объект, и передача это контекст проверки допустимости мы создали ранее:
Теперь мы готовы проверить подписи. Мы делаем это, вызывая validate
метод на XMLSignature
объект, и передача это контекст проверки допустимости следующим образом:
validate
метод возвращает "true", если подпись проверяет успешно согласно core validation rules
в W3C XML Signature Recommendation
, и ложь иначе.
Если XMLSignature.validate
метод возвращает false, мы можем попытаться сузить причину отказа. В базовой проверке допустимости XML-подписи есть две фазы:
Каждая фаза должна быть успешной для подписи, чтобы быть допустимой. Проверять, можем ли подпись, отказавшая, чтобы криптографически проверить, мы проверить состояние, следующим образом:
boolean sv = signature.getSignatureValue().validate(valContext); System.out.println("signature validation status: " + sv);
Мы можем также выполнить итерации по ссылкам и проверить состояние проверки допустимости каждого, следующим образом:
Iterator i = signature.getSignedInfo().getReferences().iterator(); for (int j=0; i.hasNext(); j++) { boolean refValid = ((Reference) i.next()).validate(valContext); System.out.println("ref["+j+"] validity status: " + refValid); }
KeySelectors
используются, чтобы найти и выбрать ключи, которые необходимы, чтобы проверить XMLSignature. Ранее, когда мы создали a DOMValidateContext
объект, мы передали a KeySelector
возразите как первый параметр:
Альтернативно, мы, возможно, передали a PublicKey
как первый параметр, если мы уже знали, какой ключ необходим, чтобы проверить подписи. Однако, мы часто не знаем.
KeyValueKeySelector
конкретная реализация краткого обзора KeySelector
класс. KeyValueKeySelector
реализация пытается счесть соответствующий ключ проверки допустимости использованием данных содержавшийся в KeyValue
элементы KeyInfo
элемент XMLSignature
. Это не определяет, доверяют ли ключу. Это - очень простое KeySelector
реализация, разработанная для иллюстрации, а не реального использования. Более практический пример a KeySelector
тот, который ищет a KeyStore
для доверяемых ключей то соответствие X509Data
информация (например, X509SubjectName
, X509IssuerSerial
, X509SKI
, или X509Certificate
элементы) содержавшийся в a KeyInfo
.
Реализация KeyValueKeySelector
следующие:
private static class KeyValueKeySelector extends KeySelector { public KeySelectorResult select(KeyInfo keyInfo, KeySelector.Purpose purpose, AlgorithmMethod method, XMLCryptoContext context) throws KeySelectorException { if (keyInfo == null) { throw new KeySelectorException("Null KeyInfo object!"); } SignatureMethod sm = (SignatureMethod) method; List list = keyInfo.getContent(); for (int i = 0; i < list.size(); i++) { XMLStructure xmlStructure = (XMLStructure) list.get(i); if (xmlStructure instanceof KeyValue) { PublicKey pk = null; try { pk = ((KeyValue)xmlStructure).getPublicKey(); } catch (KeyException ke) { throw new KeySelectorException(ke); } // make sure algorithm is compatible with method if (algEquals(sm.getAlgorithm(), pk.getAlgorithm())) { return new SimpleKeySelectorResult(pk); } } } throw new KeySelectorException("No KeyValue element found!"); } static boolean algEquals(String algURI, String algName) { if (algName.equalsIgnoreCase("DSA") && algURI.equalsIgnoreCase(SignatureMethod.DSA_SHA1)) { return true; } else if (algName.equalsIgnoreCase("RSA") && algURI.equalsIgnoreCase(SignatureMethod.RSA_SHA1)) { return true; } else { return false; } } }
Код, обсужденный в этом разделе, находится в GenEnveloped.java
файл в
docs/technotes/guides/security/xmldsig
каталог. Файл, на котором это работает, envelope.xml
, находится в том же самом каталоге. Это генерирует файл envelopedSignature.xml.
Чтобы скомпилировать и выполнить эту выборку, выполните следующую команду от
docs/technotes/guides/security/xmldsig
каталог:
$ javac GenEnveloped.java
$ java GenEnveloped envelope.xml envelopedSignature.xml
Пример программы генерирует окутанную подпись документа в файле envelope.xml и сохранит это в файле envelopedSignature.xml
в текущем рабочем каталоге.
Этот пример показывает Вам, как генерировать XML-подпись, используя XML API Цифровой подписи. Более определенно пример генерирует окутанную XML-подпись XML-документа. Окутанная подпись является подписью, которая содержится в контенте, который она подписывает. Пример использует ДОМА (Объектная модель документа), чтобы проанализировать XML-документ, который будет подписан и JSR 105 реализаций ДОМА, чтобы генерировать получающуюся подпись.
Элементарные знания XML-подписей и их различных компонентов полезны для того, чтобы понять этот раздел. См. http://www.w3.org/TR/xmldsig-core/
Во-первых, мы используем JAXP DocumentBuilderFactory
проанализировать XML-документ, который мы хотим подписать. Приложение получает реализацию по умолчанию для DocumentBuilderFactory
вызывая следующую строку кода:
Мы должны также сделать фабрику осведомленной о пространстве имен:
Затем, мы используем фабрику, чтобы получить экземпляр a DocumentBuilder
, который используется, чтобы проанализировать документ:
DocumentBuilder builder = dbf.newDocumentBuilder(); Document doc = builder.parse(new FileInputStream(argv[0]));
Мы генерируем пару с открытым ключом. Позже в примере, мы будем использовать закрытый ключ, чтобы генерировать подпись. Мы создаем пару ключей с a KeyPairGenerator
. В этом примере мы создадим DSA KeyPair
с длиной 512 байтов:
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA"); kpg.initialize(512); KeyPair kp = kpg.generateKeyPair();
Практически, закрытый ключ обычно ранее сгенерирован и сохранен в a KeyStore
файл со связанным сертификатом с открытым ключом.
Мы создаем XML Цифровая подпись XMLSignContext
содержа входные параметры для того, чтобы генерировать подпись. Так как мы используем ДОМА, мы инстанцируем a DOMSignContext
(подкласс XMLSignContext
), и передача это два параметра, закрытый ключ, который будет использоваться, чтобы подписать документ и корень документа, который будет подписан:
Мы собираем различные части Signature
элемент в XMLSignature
объект. Эти объекты все создаются и собрали использование XMLSignatureFactory
объект. Приложение получает реализацию ДОМА XMLSignatureFactory
вызывая следующую строку кода:
Мы тогда вызываем различные методы фабрики, чтобы создать различные части XMLSignature
возразите как показано ниже. Мы создаем a Reference
объект, передавая к этому следующее:
Затем, мы создаем SignedInfo
объект, который является объектом, который фактически подписывается, как показано ниже. Создавая SignedInfo
, мы передаем как параметры:
Затем, мы создаем дополнительное KeyInfo
объект, который содержит информацию, которая позволяет получателю найти ключ, должен был проверить подписи. В этом примере мы добавляем a KeyValue
объект, содержащий открытый ключ. Создать KeyInfo
и его различные подтипы, мы используем a KeyInfoFactory
объект, который может быть получен, вызывая getKeyInfoFactory
метод XMLSignatureFactory
, следующим образом:
Мы тогда используем KeyInfoFactory
создать KeyValue
возразите и добавьте это к a KeyInfo
объект:
KeyValue kv = kif.newKeyValue(kp.getPublic()); KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));
Наконец, мы создаем XMLSignature
объект, передавая как параметры SignedInfo
и KeyInfo
объекты, которые мы создали ранее:
Заметьте, что мы еще фактически не генерировали подпись; мы сделаем это в следующем шаге.
Теперь мы готовы генерировать подпись, которую мы делаем, вызывая sign
метод на XMLSignature
объект, и передача это контекст подписания следующим образом:
Получающийся документ теперь содержит подпись, которая была вставлена как последний дочерний элемент корневого элемента.
Можно использовать следующий код, чтобы напечатать получающийся документ со знаком файлу или стандартному выводу:
OutputStream os; if (args.length > 1) { os = new FileOutputStream(args[1]); } else { os = System.out; } TransformerFactory tf = TransformerFactory.newInstance(); Transformer trans = tf.newTransformer(); trans.transform(new DOMSource(doc), new StreamResult(os));