Spec-Zone .ru
спецификации, руководства, описания, API
|
1.0 Введение
4.0 Инструменты
Приложение Sun PKCS#11 Поддерживаемые Алгоритмы Провайдера
Приложение B Sun PKCS#11 Ограничения KeyStore Провайдера
Провайдер приложения C В качестве примера
Платформа Java определяет ряд интерфейсов программирования для того, чтобы выполнить криптографические операции. Эти интерфейсы все вместе известны как Архитектура Криптографии Java (JCA) и Расширение Криптографии Java (JCE). Спецификации доступны в Java страница Документации Безопасности SE.
Криптографические интерфейсы основаны на провайдере. Определенно, приложения говорят с Прикладными программными интерфейсами (API), и фактические криптографические операции выполняются в сконфигурированных провайдерах, которые придерживаются ряда Интерфейсов Поставщика услуг (SPI). Эта архитектура поддерживает различные реализации провайдера. Некоторые провайдеры могут выполнить криптографические операции в программном обеспечении; другие могут выполнить операции на аппаратном маркере (например на устройстве смарт-карты или на аппаратных средствах криптографический акселератор).
Криптографический Маркерный Стандарт Интерфейса, PKCS#11, производится Безопасностью RSA и определяет собственные интерфейсы программирования к криптографическим маркерам, таким как аппаратные средства криптографические акселераторы и Смарт-карты. Чтобы облегчить интеграцию собственных PKCS#11 маркеры в платформу Java, новый криптографический провайдер, Sun PKCS#11 провайдер, был введен в J2SE 5.0 выпусков. Этот новый провайдер позволяет существующим приложениям, записанным JCA и API JCE получить доступ собственный PKCS#11 маркеры. Никакие модификации к приложению не требуются. Единственное требование является надлежащей конфигурацией провайдера в Среду выполнения Java.
Хотя приложение может использовать большинство PKCS#11 функции, используя существующие API, некоторым приложениям, возможно, понадобились бы больше гибкости и возможностей. Например, приложение могло бы хотеть иметь дело со Смарт-картами, удаляемыми и вставленными динамически более легко. Или, PKCS#11 маркер мог бы потребовать аутентификации для некоторых не ключ связанные операции и поэтому, приложение должно быть в состоянии зарегистрировать в маркер, не используя keystore. В J2SE 5.0, JCA был улучшен, чтобы позволить приложениям большую гибкость имея дело с различными провайдерами.
Этот документ описывает, как собственный PKCS#11 маркеры могут быть сконфигурированы в платформу Java для использования приложениями Java. Это также описывает улучшения, которые были сделаны к JCA облегчить для приложений иметь дело с различными типами провайдеров, включая PKCS#11 провайдеры.
Sun PKCS#11 провайдер, в отличие от большинства других провайдеров, не реализует криптографические алгоритмы самостоятельно. Вместо этого это действует как мост между Java JCA и API JCE и собственным PKCS#11 криптографический API, преобразовывая вызовы и соглашения между двумя. Это означает, что приложения Java, вызывая стандартный JCA и API JCE, без модификации, могут использовать в своих интересах алгоритмы, предлагаемые базовым PKCS#11 реализации, такой как, например,
Sun PKCS#11 провайдер поддерживается на Солярисе (SPARC и x86), Linux (x86), и платформы Windows и в 32-разрядных и в 64-разрядных процессах Java.
Sun PKCS#11 провайдер требует реализации PKCS#11 v2.0 или позже быть установленным на системе. Эта реализация должна принять форму совместно используемой библиотеки объектов (.so на Солярисе и Linux) или динамически подключаемая библиотека (.dll на Windows). Пожалуйста, консультируйтесь со своей документацией поставщика, чтобы узнать, включает ли Ваше криптографическое устройство такой PKCS#11 реализация, как сконфигурировать это, и каково имя файла библиотеки.
Sun PKCS#11 провайдер поддерживает много алгоритмов, при условии, что базовое PKCS#11 реализация предлагает им. Алгоритмы и их соответствие PKCS#11 механизмы перечисляются в таблице в Приложении A.
sun.security.pkcs11.SunPKCS11
и принимает полный путь конфигурационного файла как параметр. Чтобы использовать провайдера, следует сначала установить это при использовании Архитектуры Криптографии Java (JCA). Как со всеми провайдерами JCA, установка провайдера может быть сделана или статически или программно. Чтобы установить провайдера статически, добавьте провайдера к файлу свойств Security Java ($JAVA_HOME/lib/security/java.security). Например, вот фрагмент файла java.security, который устанавливает Sun PKCS#11 провайдер с конфигурационным файлом /opt/bar/cfg/pkcs11.cfg. # configuration for security providers 1-6 ommitted security.provider.7=sun.security.pkcs11.SunPKCS11 /opt/bar/cfg/pkcs11.cfgЧтобы установить провайдера динамически, создайте экземпляр провайдера с соответствующим именем файла конфигурации и затем установите это. Вот пример.
String configName = "/opt/bar/cfg/pkcs11.cfg"; Provider p = new sun.security.pkcs11.SunPKCS11(configName); Security.addProvider(p);
Чтобы использовать больше чем один слот на PKCS#11 реализация, или использовать больше чем один PKCS#11 реализация, просто повторяют установку для каждого с соответствующим конфигурационным файлом. Это приведет к Sun PKCS#11 экземпляр провайдера для каждого слота каждого PKCS#11 реализация.
Конфигурационный файл является текстовым файлом, который содержит записи в следующем формате.
припишите =, оценивают допустимые значения за атрибут, и значение описываются в таблице в этом разделе. Двумя обязательными атрибутами является name и library. Вот демонстрационный конфигурационный файл.name = FooAccelerator library = /opt/foo/lib/libpkcs11.soКомментарии обозначаются строками, запускающимися с # (число) символ.
Атрибут | Значение | Описание |
---|---|---|
библиотека | путь PKCS#11 реализация | Это - полный путь (включая расширение) PKCS#11 реализация; формат пути является зависимой платформой. Например, /opt/foo/lib/libpkcs11.so мог бы быть путь PKCS#11 реализация на Солярисе и Linux в то время как C:\foo\mypkcs11.dll мог бы быть путь на Windows. |
имя | суффикс имени этого экземпляра провайдера | Эта строка связывается с префиксным SunPKCS11-, чтобы произвести это имя экземпляра провайдера (то есть, строка, возвращенная Provider.getName() метод). Например, если атрибутом name будет "FooAccelerator", то имя экземпляра провайдера будет "SunPKCS11-FooAccelerator" . |
описание | описание этого экземпляра провайдера | Эта строка будет возвращена экземпляром провайдера Provider.getInfo() метод. Если ни один не будет определен, то описание значения по умолчанию будет возвращено. |
слот | идентификатор слота | Это - идентификатор слота, с которым должен быть связан этот экземпляр провайдера. Например, Вы использовали бы 1 для слота с идентификатором 1 под PKCS#11. Самое большее один из slot или slotListIndex может быть определен. Если ни один не определяется, значением по умолчанию является slotListIndex 0. |
slotListIndex | слот индексирует | Это - слот, индексируют тот этот экземпляр провайдера, должен быть связан с. Это - индексирование в список всех слотов, возвращенных PKCS#11 функция C_GetSlotList . Например, 0 указывает на первый слот в списке. Самое большее один из slot или slotListIndex может быть определен. Если ни один не определяется, значением по умолчанию является slotListIndex 0. |
enabledMechanisms | заключите в фигурные скобки включенный, разделенный от пробела список PKCS#11 механизмы, чтобы включить | Это - список PKCS#11 механизмы, которые должен использовать этот экземпляр провайдера, при условии, что они поддерживаются и Sun PKCS#11 провайдер и PKCS#11 маркер. Все другие механизмы будут проигнорированы. Каждая запись в списке является именем PKCS#11 механизм. Вот пример, который перечисляет два PKCS#11 механизмы. enabledMechanisms = { CKM_RSA_PKCS CKM_RSA_PKCS_KEY_PAIR_GEN }Самое большее один из enabledMechanisms или disabledMechanisms может быть определен. Если ни один не определяется, включенные механизмы являются теми, которые поддерживаются и Sun PKCS#11 провайдер и PKCS#11 маркер. |
disabledMechanisms | заключите в фигурные скобки включенный, разделенный от пробела список PKCS#11 механизмы, чтобы отключить | Это - список PKCS#11 механизм, который должен проигнорировать этот экземпляр провайдера. Любой перечисленный механизм будет проигнорирован провайдером, даже если они будут поддерживаться маркером и Sun PKCS#11 провайдер. Строки SecureRandom и KeyStore может быть определен, чтобы отключить те службы. Самое большее один из enabledMechanisms или disabledMechanisms может быть определен. Если ни один не определяется, включенные механизмы являются теми, которые поддерживаются и Sun PKCS#11 провайдер и PKCS#11 маркер. |
атрибуты | см. ниже | Опция attributes может использоваться, чтобы определить дополнительный PKCS#11, который должен быть установлен, создавая PKCS#11 ключевые объекты. Это позволяет разместить маркеры, которые требуют определенных атрибутов. Для получения дополнительной информации см. раздел ниже. |
Опция attributes может использоваться, если Вам не нравятся значения по умолчанию Ваш PKCS#11, реализация присваивается или если Ваш PKCS#11 реализация не поддерживает значения по умолчанию и требует, чтобы значение было определено явно. Отметьте, что определение атрибутов, что Ваш PKCS#11 реализация не поддерживает или которые недопустимы для типа рассматриваемого ключа, может заставить работу перестать работать во времени выполнения.
Опция может быть определена нуль или больше раз, опции обрабатываются в порядке, определенном в конфигурационном файле как описано ниже. У опции attributes есть формат:
attributes(operation, keytype, keyalgorithm) = { name1 = value1 [...] }Допустимые значения для operation:
Допустимые значения для keyalgorithm являются одной из констант CKK_xxx от PKCS#11 спецификация, или *, чтобы соответствовать ключи любого алгоритма. Алгоритмы, в настоящий момент поддерживаемые провайдером SunPKCS11, являются CKK_RSA, CKK_DSA, CKK_DH, CKK_AES, CKK_DES, CKK_DES3, CKK_RC4, CKK_BLOWFISH, и CKK_GENERIC.
Названия атрибута и значения определяются как список одной или более пар значение-имя. name должен быть CKA_xxx, постоянный от PKCS#11 спецификация, например CKA_SENSITIVE. value может быть одним из следующего:
attributes(*,CKO_PRIVATE_KEY,*) = { CKA_SIGN = true } attributes(*,CKO_PRIVATE_KEY,CKK_DH) = { CKA_SIGN = null } attributes(*,CKO_PRIVATE_KEY,CKK_RSA) = { CKA_DECRYPT = true }Первая запись говорит, чтобы определить CKA_SIGN = true для всех закрытых ключей. Вторые переопределения опции, что с null для закрытых ключей Diffie-Hellman, таким образом, атрибут CKA_SIGN не будет определенный для них вообще. Наконец, третья опция говорит, чтобы также определить CKA_DECRYPT = true для закрытых ключей RSA. Это означает, что у закрытых ключей RSA будут и CKA_SIGN = true и набор CKA_DECRYPT = true.
Есть также специальная форма опции attributes. Можно записать attributes = compatibility в конфигурационном файле. Это - ярлык для целого набора операторов атрибута. Они разрабатываются к совместимости максимума провайдера с существующими приложениями Java, которые могут ожидать, например, что все ключевые компоненты будут доступными и секретными ключами, чтобы быть применимыми и для шифрования и для дешифрования. Строка атрибутов compatibility может использоваться вместе с другими строками attributes, когда та же самая агрегация и переопределяющие правила применяются как описано ранее.
Для лучших результатов мы рекомендуем, чтобы Вы использовали последнюю версию доступного NSS. Это должна быть, по крайней мере, версия 3.12.
Sun PKCS#11 провайдер использует определенный код NSS когда любой из nss
конфигурационные директивы, описанные ниже, используются. В этом случае, регулярные команды конфигурации library
, slot
, и slotListIndex
не может использоваться.
Атрибут | Значение | Описание |
---|---|---|
nssLibraryDirectory | каталог, содержащий NSS и библиотеки NSPR | Это - полный путь каталога, содержащего NSS и библиотеки В зависимости от Вашей платформы Вам, вероятно, придется установить |
nssSecmodDirectory | каталог, содержащий файлы DB NSS | Полный путь каталога, содержащего конфигурацию NSS и ключевую информацию (secmod.db , key3.db , и cert8.db ). Это направляющее должно быть определено, если NSS не был уже инициализирован другим компонентом (см. выше), или NSS используется без файлов базы данных как описано ниже. |
nssDbMode | один из readWrite , readOnly , и noDb |
Это, которое определяют директивы, как к базе данных NSS получают доступ. В режиме чтения-записи полный доступ возможен, но только один процесс за один раз должен получать доступ к базам данных. Режим только для чтения отвергает модификации к файлам. noDb режим позволяет NSS использоваться без файлов базы данных просто как криптографический провайдер. Не возможно создать персистентные ключи, используя KeyStore PKCS11. Этот режим полезен, потому что NSS включает чрезвычайно оптимизированные реализации и алгоритмы, не в настоящий момент доступные в связанном Java Sun базируемые crypto провайдеры, например Шифрование в эллиптических кривых (ECC). |
nssModule | один из keystore , crypto , fips , и trustanchors |
NSS делает свою функциональность доступным использованием нескольких различных библиотек и слотов. Это направляющее определяет, к какому из этих модулей получает доступ этот экземпляр SunPKCS11. |
name = NSScrypto nssLibraryDirectory = /opt/tests/nss/lib nssDbMode = noDb attributes = compatibility
name = NSSfips nssLibraryDirectory = /opt/tests/nss/lib nssSecmodDirectory = /opt/tests/nss/fipsdb nssModule = fips
Приложения Java могут использовать существующий JCA и API JCE к доступу PKCS#11 маркеры через Sun PKCS#11 провайдер. Это достаточно для многих приложений, но для приложения могло бы быть трудно иметь дело с определенным PKCS#11 функции, такие как неизвлекаемые ключи и динамически изменяющий Смарт-карты. Следовательно, много улучшений были сделаны к API лучше поддерживать приложения, использующие бесспорный PKCS#11 функции. Эти enhancments обсуждаются в этом разделе.
Бесспорный PKCS#11 операции, такие как доступ к закрытым ключам, требуют входа в систему, используя Персональный идентификационный номер, или ПИН, прежде, чем операции смогут продолжиться. Наиболее распространенный тип операций, которые требуют входа в систему, является теми, которые имеют дело с, включает маркер. В приложении Java такие операции часто включают сначала загрузку keystore. Получая доступ PKCS#11 маркер как keystore через java.security.KeyStore class, можно предоставить ПИН во входном параметре пароля к методу загрузки, подобному тому, как приложения инициализируют keystore до J2SE 5.0. ПИН будет тогда использоваться Sun PKCS#11 провайдер для того, чтобы зарегистрировать в маркер. Вот пример.
char[] pin = ...; KeyStore ks = KeyStore.getInstance("PKCS11"); ks.load(null, pin);
Это прекрасно для приложения, которое обрабатывает PKCS#11 маркеры как статический keystores. Для приложения, которое хочет разместить PKCS#11 маркеры более динамически, такие как Смарт-карты, вставляемые и удаленные, можно использовать новый KeyStore.Builder class. Вот пример того, как инициализировать разработчика для PKCS#11 keystore с обработчиком обратного вызова.
KeyStore.CallbackHandlerProtection chp = new KeyStore.CallbackHandlerProtection(new MyGuiCallbackHandler()); KeyStore.Builder builder = KeyStore.Builder.newInstance("PKCS11", null, chp);
Для Sun PKCS#11 провайдер, обработчик обратного вызова должен быть в состоянии удовлетворить PasswordCallback, который используется, чтобы запросить пользователя ПИН. Всякий раз, когда приложение нуждается в доступе к keystore, это использует разработчика следующим образом.
KeyStore ks = builder.getKeyStore(); Key key = ks.getKey(alias, null);
Разработчик запросит пароль как необходимый использование ранее сконфигурированного обработчика обратного вызова. Разработчик запросит пароль только для начального доступа. Если пользователь приложения будет продолжать использовать ту же самую Смарт-карту, то пользователь не будет запрошен снова. Если пользователь удалит и введет различный SmartCard, то разработчик запросит пароль для новой карты.
В зависимости от PKCS#11 маркер, могут быть не ключевые связанные операции, которые также требуют маркерного входа в систему. Приложения, которые используют такие операции, могут использовать недавно представленный java.security.AuthProvider class. AuthProvider class расширяется от java.security.Provider и определяет методы, чтобы выполнить операции входа в систему и выхода из системы на провайдере, так же как установить обработчик обратного вызова для провайдера, чтобы использовать.
Для Sun PKCS#11 провайдер, обработчик обратного вызова должен быть в состоянии удовлетворить PasswordCallback, который используется, чтобы запросить пользователя ПИН.
Вот пример того, как приложение могло бы использовать AuthProvider, чтобы зарегистрировать в маркер.
AuthProvider aprov = (AuthProvider)Security.getProvider("SunPKCS11"); aprov.login(subject, new MyGuiCallbackHandler());
Java Key
объекты могут или, возможно, не содержат фактический ключевой материал.
Приложения и провайдеры должны использовать корректные интерфейсы, чтобы представить эти различные типы Ключевых объектов. Ключевые объекты программного обеспечения (или любой Ключевой объект, у которого есть доступ к фактическому ключевому материалу) должны реализовать интерфейсы в java.security.interfaces и javax.crypto.interfaces пакетах (таких как DSAPrivateKey). Ключевые объекты, представляющие неизвлекаемые маркерные ключи, должны только реализовать соответствующие универсальные интерфейсы в java.security и javax.crypto пакетах (PrivateKey, PublicKey, или SecretKey). Идентификация алгоритма ключа должна быть выполнена, используя метод Key.getAlgorithm().
Приложения должны отметить, что Ключевой объект для неизвлекаемого маркерного ключа может только использоваться провайдером, связанным с тем маркером.
До J2SE 5.0, методы getInstance() криптографии Java, такие как Cipher.getInstance("DES"), возвратили реализацию из первого провайдера, который реализовывал требуемый алгоритм. Это проблематично, если приложение пытается использовать объект Key для неизвлекаемого маркерного ключа с провайдером, который только принимает ключевые объекты программного обеспечения. В таком случае провайдер бросил бы InvalidKeyException. Это - проблема для Cipher, KeyAgreement, Mac, и классов Signature.
J2SE 5.0, решает эту проблему, задерживая выбор провайдера, пока соответствующий метод инициализации не вызывают. Метод инициализации принимает объект Key и может определить в той точке, какой провайдер может принять указанный объект Key. Это гарантирует, что выбранный провайдер может использовать указанный объект Key. Следующее представляет методы инициализации, на которые влияют.
Хотя этот задержанный выбор провайдера скрывается от приложения, он действительно влияет на поведение getProvider()
метод для Cipher, KeyAgreement, Mac, и Signature. Если getProvider()
вызывается прежде, чем работа инициализации произошла (и поэтому прежде, чем выбор провайдера произошел), тогда первый провайдер, который поддерживает требуемый алгоритм, возвращается. Это, возможно, не тот же самый провайдер как то, выбранное после того, как метод инициализации вызывают. Если getProvider()
вызывается после того, как работа инициализации произошла, тогда фактический выбранный провайдер возвращается. Этому рекомендуют это, приложения только вызывают getProvider()
после того, как они вызвали соответствующий метод инициализации.
В дополнение к getProvider()
, на следующие дополнительные методы так же влияют.
Используйте следующие опции, чтобы сконфигурировать KeyStoreLoginModule, чтобы использовать PKCS#11 маркер как keystore.
other { com.sun.security.auth.module.KeyStoreLoginModule required keyStoreURL="NONE" keyStoreType="PKCS11" keyStorePasswordURL="file:/home/joe/scpin"; };
Если больше чем один Sun PKCS#11 провайдер был сконфигурирован динамически или в файле свойств безопасности java.security, можно использовать опцию keyStoreProvider, чтобы предназначаться для определенного экземпляра провайдера. Параметром этой опции является имя провайдера. Для Sun PKCS#11 провайдер, имя провайдера имеет форму SunPKCS11-TokenName, где TokenName является суффиксом имени, что экземпляр провайдера был сконфигурирован с, как детализировано в таблице атрибутов конфигурации. Например, следующий конфигурационный файл называет PKCS#11, экземпляр провайдера с именем снабжает суффиксом SmartCard.
other { com.sun.security.auth.module.KeyStoreLoginModule required keyStoreURL="NONE" keyStoreType="PKCS11" keyStorePasswordURL="file:/home/joe/scpin" keyStoreProvider="SunPKCS11-SmartCard"; };
Некоторые PKCS#11 маркеры поддерживают вход в систему через защищенный путь аутентификации. Например, у Смарт-карты может быть выделенная клавиатура ПИН, чтобы ввести контакт. У биометрических устройств также будут свои средства собственного получить информацию об аутентификации. Если PKCS#11 у маркера есть защищенный путь аутентификации, то используйте опцию protected=true и опустите опцию keyStorePasswordURL. Вот пример конфигурационного файла для такого маркера.
other { com.sun.security.auth.module.KeyStoreLoginModule required keyStoreURL="NONE" keyStoreType="PKCS11" protected=true; };
JSSE также поддерживает конфигурирование использования keystores и баз доверенных сертификатов через системные свойства, как описано в Справочнике JSSE. Чтобы использовать PKCS#11 маркер как keystore или база доверенных сертификатов, установите javax.net.ssl.keyStoreType и системные свойства javax.net.ssl.trustStoreType, соответственно, к "PKCS11", и установите javax.net.ssl.keyStore и системные свойства javax.net.ssl.trustStore, соответственно, к NONE. Чтобы определить использование определенного экземпляра провайдера, используйте javax.net.ssl.keyStoreProvider и системные свойства javax.net.ssl.trustStoreProvider (например, "SunPKCS11-смарт-карта").
В J2SE 5.0, средства обеспечения безопасности были обновлены, чтобы поддерживать операции, используя новый Sun PKCS#11 провайдер. Изменения обсуждаются ниже.
Если Sun PKCS#11 провайдер был сконфигурирован в файле свойств безопасности java.security (расположенный в каталоге $JAVA_HOME/lib/security Среды выполнения Java), то keytool и jarsigner могут использоваться, чтобы работать на PKCS#11 маркер, определяя следующие опции.
keytool -keystore NONE -storetype PKCS11 -listПИН может быть определен, используя-storepass опцию. Если ни один не был определен, то keytool и jarsigner запросят маркерный ПИН. Если у маркера есть защищенный путь аутентификации (такой как выделенная клавиатура ПИН или биометрический читатель), то опция -protected должна быть определена, и никакие опции пароля не могут быть определены.
Если больше чем один Sun PKCS#11 провайдер был сконфигурирован в файле свойств безопасности java.security, можно использовать опцию -providerName, чтобы предназначаться для определенного экземпляра провайдера. Параметром этой опции является имя провайдера.
keytool -keystore NONE -storetype PKCS11 \ -providerName SunPKCS11-SmartCard \ -list
Если Sun PKCS#11 провайдер не был сконфигурирован в файле свойств безопасности java.security, можно использовать следующие опции, чтобы дать команду keytool и jarsigner устанавливать провайдера динамически.
keytool -keystore NONE -storetype PKCS11 \ -providerClass sun.security.pkcs11.SunPKCS11 \ -providerArg /foo/bar/token.config \ -list
До J2SE 5.0, у keystore записи в реализации политики значения по умолчанию был следующий синтаксис.
keystore "some_keystore_url", "keystore_type";Этот синтаксис был несоответствующим для того, чтобы получить доступ PKCS#11 keystore потому что такой доступ, обычно требуемый ПИН, и могло бы быть многократно PKCS#11 экземпляры провайдера. Чтобы разместить эти требования, keystore синтаксис записи был обновлен в J2SE 5.0 к следующему.
keystore "some_keystore_url", "keystore_type", "keystore_provider"; keystorePasswordURL "some_password_url";Где keystore_provider является keystore именем провайдера (например, "SunPKCS11-SmartCard"), и some_password_url является URL, указывающий на расположение маркерного ПИН. И keystore_provider и keystorePasswordURL строка являются дополнительными. Если keystore_provider не был определен, то первый сконфигурированный провайдер, который поддерживает указанный тип keystore, используется. Если строка keystorePasswordURL не была определена, то никакой пароль не используется.
Следующее является примером keystore запись политики для PKCS#11 маркер.
keystore "NONE", "PKCS11", "SunPKCS11-SmartCard"; keystorePasswordURL "file:/foo/bar/passwordFile";
J2SE 5.0 представляет новые средства в java.security. Провайдер class для реализаций провайдера, чтобы более легко поддерживать PKCS#11 маркеры и криптографические службы вообще. Эти новые средства обсуждаются ниже.
См. Приложение C для примера простого провайдера, разработанного, чтобы демонстрировать новый facilties.
Как описано в вышеупомянутой документации провайдера, до J2SE 5.0, провайдеры были обязаны создавать записи java.util.Property, описывающие службы, которые они поддерживали. Для каждой службы, реализованной провайдером, должно быть свойство, имя которого является типом службы (Cipher, Signature, и т.д.), сопровождаемый периодом и именем алгоритма, к которому применяется служба. Значение свойства должно определить полностью определенное имя class, реализовывая службу. Вот пример свойства установки KeyAgreement.DiffieHellman провайдера, чтобы иметь значение com.sun.crypto.provider.DHKeyAgreement.
put("KeyAgreement.DiffieHellman", "com.sun.crypto.provider.DHKeyAgreement")
J2SE 5.0 представляет новый общедоступный статический вложенный class, Provider.Service, чтобы помочь лучше инкапсулировать свойства службы провайдера (включая ее тип, атрибуты, имя алгоритма, и псевдонимы алгоритма). Провайдеры могут инстанцировать объектов Provider.Service и зарегистрировать их, вызывая метод Provider.putService(). Это эквивалентно созданию записи Property и вызову метода Provider.put() (как был сделан до J2SE 5.0). Отметьте, что наследство записи Property, зарегистрированные через Provider.put, все еще поддерживается.
Вот пример провайдера, создающего объект Service с типом KeyAgreement, для алгоритма DiffieHellman, реализованного class com.sun.crypto.provider.DHKeyAgreement.
Service s = new Service(this, "KeyAgreement", "DiffieHellman", "com.sun.crypto.provider.DHKeyAgreement", null, null); putService(s);
Используя объекты Provider.Servicee вместо наследства записи Property обладает несколькими главными преимуществами. Одно преимущество - то, что это позволяет провайдеру иметь большую гибкость, инстанцируя классов механизма. Другое преимущество - то, что это позволяет провайдеру тестировать законность параметра. Эти функции обсуждаются подробно затем.
До J2SE 5.0, платформа Криптографии Java, искавшая свойство провайдера для определенной службы и непосредственно инстанцированный механизм, class зарегистрировался для того свойства. J2SE 5.0, имеет то же самое поведение по умолчанию, но позволяет провайдеру переопределять это поведение и инстанцировать механизма class для требуемой службы непосредственно.
Чтобы переопределить поведение значения по умолчанию, провайдер переопределяет метод Provider.Service.newInstance(), чтобы добавить его потребительское поведение. Например, провайдер мог бы вызвать пользовательского конструктора, или мог бы выполнить инициализацию, используя информацию, не доступную вне провайдера (или которые только известны провайдером).
Платформа Криптографии Java может делать попытку быстрой проверки, чтобы определить, может ли реализация службы провайдера использовать определенный приложением параметр. Чтобы выполнить эту быструю проверку, платформа вызывает Provider.Service.supportsParameter().
В J2SE 5.0, платформа полагается на этот быстрый тест во время задержанного выбора провайдера. Когда приложение вызывает метод инициализации и передает его объект Key, платформа спрашивает базового провайдера, поддерживает ли он объект, вызывая его метод Service.supportsParameter(). Если supportsParameter()
возвраты false
, платформа может сразу удалить того провайдера из рассмотрения. Если supportsParameter()
возвраты true
, платформа передает объект Key к механизму инициализации того провайдера реализация class. Провайдер, который требует программного обеспечения объекты Key, должен переопределить этот метод, чтобы возвратиться false
когда это - переданные ключи непрограммного обеспечения. Аналогично, провайдер для PKCS#11 маркер, который содержит неизвлекаемые ключи, должен только возвратиться true
поскольку Key возражает, что создал, и которые поэтому соответствуют Key s на его соответствующем маркере.
Отметьте что реализация по умолчанию supportsParameter()
возвраты true
. Это позволяет существующим провайдерам работать без модификации. Однако, из-за этой снисходительной реализации по умолчанию, платформа должна быть подготовлена поймать исключения, выданные провайдерами, которые отклоняют объект Key в их механизме инициализации реализации class. Платформа обрабатывает эти случаи то же самое как тогда, когда supportsParameter()
возвраты false
.
disabledMechanisms
и enabledMechanisms
конфигурационные директивы. Для механизмов Эллиптической кривой SunPKCS11 будет только использовать ключи, которые используют namedCurve
выбор как кодирующий для параметров и только позволяет несжатый формат точки. Sun PKCS#11 провайдер предполагает, что маркер поддерживает весь стандарт, названный параметрами домена.
Алгоритм Java | PKCS#11 Механизмы |
---|---|
Подпись. MD2withRSA | CKM_MD2_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509 |
Подпись. MD5withRSA | CKM_MD5_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509 |
Подпись. SHA1withRSA | CKM_SHA1_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509 |
Подпись. SHA256withRSA | CKM_SHA256_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509 |
Подпись. SHA384withRSA | CKM_SHA384_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509 |
Подпись. SHA512withRSA | CKM_SHA512_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509 |
Подпись. SHA1withDSA | CKM_DSA_SHA1, CKM_DSA |
Подпись. NONEwithDSA | CKM_DSA |
Подпись. SHA1withECDSA | CKM_ECDSA_SHA1, CKM_ECDSA |
Подпись. SHA256withECDSA | CKM_ECDSA |
Подпись. SHA384withECDSA | CKM_ECDSA |
Подпись. SHA512withECDSA | CKM_ECDSA |
Подпись. NONEwithECDSA | CKM_ECDSA |
Шифр. RSA/ECB/PKCS1Padding | CKM_RSA_PKCS |
Шифр. ARCFOUR | CKM_RC4 |
Шифр. DES/CBC/NoPadding | CKM_DES_CBC |
Шифр. DESede/CBC/NoPadding | CKM_DES3_CBC |
Шифр. AES/CBC/NoPadding | CKM_AES_CBC |
Шифр. Blowfish/CBC/NoPadding | CKM_BLOWFISH_CBC |
Шифр. RSA/ECB/NoPadding | CKM_RSA_X_509 |
Шифр. AES/CTR/NoPadding | CKM_AES_CTR |
KeyAgreement. ECDH | CKM_ECDH1_DERIVE |
KeyAgreement. DiffieHellman | CKM_DH_PKCS_DERIVE |
KeyPairGenerator. RSA | CKM_RSA_PKCS_KEY_PAIR_GEN |
KeyPairGenerator. DSA | CKM_DSA_KEY_PAIR_GEN |
KeyPairGenerator. EC | CKM_EC_KEY_PAIR_GEN |
KeyPairGenerator. DiffieHellman | CKM_DH_PKCS_KEY_PAIR_GEN |
KeyGenerator. ARCFOUR | CKM_RC4_KEY_GEN |
KeyGenerator. DES | CKM_DES_KEY_GEN |
KeyGenerator. DESede | CKM_DES3_KEY_GEN |
KeyGenerator. AES | CKM_AES_KEY_GEN |
KeyGenerator. Шифр | CKM_BLOWFISH_KEY_GEN |
Mac. HmacMD5 | CKM_MD5_HMAC |
Mac. HmacSHA1 | CKM_SHA_1_HMAC |
Mac. HmacSHA256 | CKM_SHA256_HMAC |
Mac. HmacSHA384 | CKM_SHA384_HMAC |
Mac. HmacSHA512 | CKM_SHA512_HMAC |
MessageDigest. MD2 | CKM_MD2 |
MessageDigest. MD5 | CKM_MD5 |
MessageDigest. SHA1 | CKM_SHA_1 |
MessageDigest. SHA 256 | CKM_SHA256 |
MessageDigest. SHA 384 | CKM_SHA384 |
MessageDigest. SHA 512 | CKM_SHA512 |
KeyFactory. RSA | Любой поддерживал механизм RSA |
KeyFactory. DSA | Любой поддерживаемый механизм DSA |
KeyFactory. EC | Любой поддерживал механизм EC |
KeyFactory. DiffieHellman | Любой поддерживал механизм Diffie-Hellman |
SecretKeyFactory. ARCFOUR | CKM_RC4 |
SecretKeyFactory. DES | CKM_DES_CBC |
SecretKeyFactory. DESede | CKM_DES3_CBC |
SecretKeyFactory. AES | CKM_AES_CBC |
SecretKeyFactory. Шифр | CKM_BLOWFISH_CBC |
SecureRandom. PKCS11 | У CK_TOKEN_INFO есть набор битов CKF_RNG |
KeyStore. PKCS11 | Всегда доступный |
Следующее описывает требования, помещенные Sun PKCS#11 реализация KeyStore Провайдера на базовом собственном PKCS#11 библиотека. Отметьте, что изменения могут быть произведены в будущих выпусках, чтобы максимизировать функциональную совместимость с так многими существующими PKCS#11 библиотеки насколько возможно.
Чтобы отобразить существующие объекты, хранившие на PKCS#11 маркер к записям KeyStore, Sun PKCS#11, реализация KeyStore Провайдера выполняет следующие операции.
Для каждой пары соответствия цепочка сертификата создается следующим выпускающий-> подчиненный путь. От сертификата объекта конца вызов fo C_FindObjects [Init|Final] выполняется с шаблоном поиска, который включает следующие атрибуты:
Этот поиск продолжается, или ни до какой сертификат для выпускающего не находится, или до пока самоподписанный сертификат находится. Если больше чем один сертификат находится, первый используется.
Как только закрытый ключ и сертификат были соответствующими (и его созданная цепочка сертификата), информация хранится в записи с закрытым ключом со значением CKA_LABEL от сертификата объекта конца как псевдоним KeyStore.
Если у сертификата объекта конца нет никакого CKA_LABEL, то псевдоним получается из CKA_ID. Если CKA_ID может быть решен состоять исключительно из печатаемых символов, то Строковый псевдоним создается, декодируя байты CKA_ID, используя набор символов UTF-8. Иначе, шестнадцатеричный Строковый псевдоним создается из байтов CKA_ID ("0xFFFF...", например).
Если многократные сертификаты совместно используют тот же самый CKA_LABEL, то псевдоним получается из CKA_LABEL плюс выпускающий сертификата объекта конца и порядковый номер ("MyCert/CN=foobar/1234", например).
Если атрибут CKA_TRUSTED не поддерживается тогда, никакие доверяемые записи сертификата не создаются.
Запись секретного ключа KeyStore создается для каждого объекта секретного ключа со значением CKA_LABEL как псевдоним KeyStore. У каждого объекта секретного ключа должен быть уникальный CKA_LABEL.
Чтобы создать новые записи KeyStore на PKCS#11 маркер к записям KeyStore, Sun PKCS#11, реализация KeyStore Провайдера выполняет следующие операции.
Объекты с закрытым ключом хранятся с CKA_PRIVATE=true. (UTF8-закодированный) псевдоним KeyStore устанавливается как CKA_ID и для закрытого ключа и для соответствующего сертификата объекта конца. Псевдоним KeyStore также устанавливается как CKA_LABEL для объекта сертификата объекта конца.
Каждый сертификат в цепочке записи с закрытым ключом также сохранен. CKA_LABEL не устанавливается для сертификатов CA. Если сертификат CA уже находится в маркере, копия не сохранена.
Объекты секретного ключа хранятся с CKA_PRIVATE=true. Псевдоним KeyStore устанавливается как CKA_LABEL.
В дополнение к упомянутым выше поискам следующие поискы могут использоваться Sun PKCS#11 реализация KeyStore провайдера, чтобы выполнить внутренние функции. Определенно, C_FindObjects [Init|Final] можно вызвать с любым из следующих шаблонов атрибута:
CKA_TOKEN true CKA_CLASS CKO_CERTIFICATE CKA_SUBJECT [subject DN]
CKA_TOKEN true CKA_CLASS CKO_SECRET_KEY CKA_LABEL [label]
CKA_TOKEN true CKA_CLASS CKO_CERTIFICATE or CKO_PRIVATE_KEY CKA_ID [cka_id]
package com.foo; import java.io.*; import java.lang.reflect.*; import java.security.*; import javax.crypto.*; /** * Example provider that demonstrates some of the new API features. * * . implement multiple different algorithms in a single class. * Previously each algorithm needed to be implemented in a separate class * (e.g. one for MD5, one for SHA-1, etc.) * * . multiple concurrent instances of the provider frontend class each * associated with a different backend. * * . it uses "unextractable" keys and lets the framework know which key * objects it can and cannot support * * Note that this is only a simple example provider designed to demonstrate * several of the new features. It is not explicitly designed for efficiency. */ public final class ExampleProvider extends Provider { // reference to the crypto backend that implements all the algorithms final CryptoBackend cryptoBackend; public ExampleProvider(String name, CryptoBackend cryptoBackend) { super(name, 1.0, "JCA/JCE provider for " + name); this.cryptoBackend = cryptoBackend; // register the algorithms we support (MD5, SHA1, DES, and AES) putService(new MyService (this, "MessageDigest", "MD5", "com.foo.ExampleProvider$MyMessageDigest")); putService(new MyService (this, "MessageDigest", "SHA1", "com.foo.ExampleProvider$MyMessageDigest")); putService(new MyCipherService (this, "Cipher", "DES", "com.foo.ExampleProvider$MyCipher")); putService(new MyCipherService (this, "Cipher", "AES", "com.foo.ExampleProvider$MyCipher")); } // the API of our fictitious crypto backend static abstract class CryptoBackend { abstract byte[] digest(String algorithm, byte[] data); abstract byte[] encrypt(String algorithm, KeyHandle key, byte[] data); abstract byte[] decrypt(String algorithm, KeyHandle key, byte[] data); abstract KeyHandle createKey(String algorithm, byte[] keyData); } // the shell of the representation the crypto backend uses for keys private static final class KeyHandle { // fill in code } // we have our own ServiceDescription implementation that overrides newInstance() // that calls the (Provider, String) constructor instead of the no-args constructor private static class MyService extends Service { private static final Class[] paramTypes = {Provider.class, String.class}; MyService(Provider provider, String type, String algorithm, String className) { super(provider, type, algorithm, className, null, null); } public Object newInstance(Object param) throws NoSuchAlgorithmException { try { // get the Class object for the implementation class Class clazz; Provider provider = getProvider(); ClassLoader loader = provider.getClass().getClassLoader(); if (loader == null) { clazz = Class.forName(getClassName()); } else { clazz = loader.loadClass(getClassName()); } // fetch the (Provider, String) constructor Constructor cons = clazz.getConstructor(paramTypes); // invoke constructor and return the SPI object Object obj = cons.newInstance(new Object[] {provider, getAlgorithm()}); return obj; } catch (Exception e) { throw new NoSuchAlgorithmException("Could not instantiate service", e); } } } // custom ServiceDescription class for Cipher objects. See supportsParameter() below private static class MyCipherService extends MyService { MyCipherService(Provider provider, String type, String algorithm, String className) { super(provider, type, algorithm, className); } // we override supportsParameter() to let the framework know which // keys we can support. We support instances of MySecretKey, if they // are stored in our provider backend, plus SecretKeys with a RAW encoding. public boolean supportsParameter(Object obj) { if (obj instanceof SecretKey == false) { return false; } SecretKey key = (SecretKey)obj; if (key.getAlgorithm().equals(getAlgorithm()) == false) { return false; } if (key instanceof MySecretKey) { MySecretKey myKey = (MySecretKey)key; return myKey.provider == getProvider(); } else { return "RAW".equals(key.getFormat()); } } } // our generic MessageDigest implementation. It implements all digest // algorithms in a single class. We only implement the bare minimum // of MessageDigestSpi methods private static final class MyMessageDigest extends MessageDigestSpi { private final ExampleProvider provider; private final String algorithm; private ByteArrayOutputStream buffer; MyMessageDigest(Provider provider, String algorithm) { super(); this.provider = (ExampleProvider)provider; this.algorithm = algorithm; engineReset(); } protected void engineReset() { buffer = new ByteArrayOutputStream(); } protected void engineUpdate(byte b) { buffer.write(b); } protected void engineUpdate(byte[] b, int ofs, int len) { buffer.write(b, ofs, len); } protected byte[] engineDigest() { byte[] data = buffer.toByteArray(); byte[] digest = provider.cryptoBackend.digest(algorithm, data); engineReset(); return digest; } } // our generic Cipher implementation, only partially complete. It implements // all cipher algorithms in a single class. We implement only as many of the // CipherSpi methods as required to show how it could work private static abstract class MyCipher extends CipherSpi { private final ExampleProvider provider; private final String algorithm; private int opmode; private MySecretKey myKey; private ByteArrayOutputStream buffer; MyCipher(Provider provider, String algorithm) { super(); this.provider = (ExampleProvider)provider; this.algorithm = algorithm; } protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException { this.opmode = opmode; myKey = MySecretKey.getKey(provider, algorithm, key); if (myKey == null) { throw new InvalidKeyException(); } buffer = new ByteArrayOutputStream(); } protected byte[] engineUpdate(byte[] b, int ofs, int len) { buffer.write(b, ofs, len); return new byte[0]; } protected int engineUpdate(byte[] b, int ofs, int len, byte[] out, int outOfs) { buffer.write(b, ofs, len); return 0; } protected byte[] engineDoFinal(byte[] b, int ofs, int len) { buffer.write(b, ofs, len); byte[] in = buffer.toByteArray(); byte[] out; if (opmode == Cipher.ENCRYPT_MODE) { out = provider.cryptoBackend.encrypt(algorithm, myKey.handle, in); } else { out = provider.cryptoBackend.decrypt(algorithm, myKey.handle, in); } buffer = new ByteArrayOutputStream(); return out; } // code for remaining CipherSpi methods goes here } // our SecretKey implementation. All our keys are stored in our crypto // backend, we only have an opaque handle available. There is no // encoded form of these keys. private static final class MySecretKey implements SecretKey { final String algorithm; final Provider provider; final KeyHandle handle; MySecretKey(Provider provider, String algorithm, KeyHandle handle) { super(); this.provider = provider; this.algorithm = algorithm; this.handle = handle; } public String getAlgorithm() { return algorithm; } public String getFormat() { return null; // this key has no encoded form } public byte[] getEncoded() { return null; // this key has no encoded form } // Convert the given key to a key of the specified provider, if possible static MySecretKey getKey(ExampleProvider provider, String algorithm, Key key) { if (key instanceof SecretKey == false) { return null; } // algorithm name must match if (!key.getAlgorithm().equals(algorithm)) { return null; } // if key is already an instance of MySecretKey and is stored // on this provider, return it right away if (key instanceof MySecretKey) { MySecretKey myKey = (MySecretKey)key; if (myKey.provider == provider) { return myKey; } } // otherwise, if the input key has a RAW encoding, convert it if (!"RAW".equals(key.getFormat())) { return null; } byte[] encoded = key.getEncoded(); KeyHandle handle = provider.cryptoBackend.createKey(algorithm, encoded); return new MySecretKey(provider, algorithm, handle); } } }