Java — PKCS11 и MSKeyStore

#java #security #keystore #pkcs#11

#java #Безопасность #хранилище ключей #pkcs#11

Вопрос:

Я пытаюсь подписать строку разными сертификатами из MS-KeyStore. Но я знаю, что в MS-Keystore есть импортированные ключи из токена. Итак, моя проблема в том, что если я захожу в хранилище ключей и пытаюсь выполнить подпись с помощью сертификата, который имеет ссылку на pkcs11, я получаю всплывающее окно для ввода пароля pkcs11. Как я могу проверить, получен ли сертификат от моего токена?

Заранее спасибо!!!

На данный момент это мой код:

   String alias;
    byte[] data = "test".getBytes();
    char[] pin = "pass".toCharArray();

    try {


        KeyStore ks = KeyStore.getInstance("Windows-MY");
        ks.load(null, pin);
        System.out.println("Provider: " ks.getProvider());
        System.out.println("KS size: "   ks.size());

        Enumeration enumeration = ks.aliases();

        while (enumeration.hasMoreElements()) {
            alias = (String) enumeration.nextElement();

            PrivateKey privateKey = (PrivateKey) ks.getKey(alias, null);
            Certificate certificate = ks.getCertificate(alias);

            Provider provider = ks.getProvider();
            Signature signature = Signature.getInstance("SHA1withRSA", provider);
            try {
                signature.initSign(privateKey);
                signature.update(data);

                byte[] signedSignature = signature.sign();
                System.out.println("tGenerated signature for "   alias);

                signature.initVerify(certificate);
                signature.update(data);
                if (signature.verify(signedSignature)) {
                    System.out.println("tSignature verifified for "   alias);
                } else {
                    System.out.println("tCould not verify signature for "   alias);
                }
            } catch (Exception ex) {
                System.out.println("tError for "   alias);
            }

        }

    } catch (KeyStoreException e) {
        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
    } catch (CertificateException e) {
        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
    } catch (FileNotFoundException e) {
        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
    } catch (IOException e) {
        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
    } catch (UnrecoverableKeyException e) {
        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
    }
  

Комментарии:

1. Ну, я не очень хорошо понимаю. В чем ваша проблема, если «появляется всплывающее окно с просьбой ввести пароль»? Если сертификат получен от внешнего токена, он будет использоваться следующим образом: при получении содержимого HSM требуется пароль. Могу ли я сказать, что вы хотите отличать сертификат внешнего токена от сертификатов «soft» / импортированных в IE?

Ответ №1:

Боюсь, вы не можете достоверно указать источник сертификата, по крайней мере, не на уровне Java для поставщика MS CAPI. Но это часть дизайна — MS CAPI более или менее намеревается инкапсулировать и скрыть происхождение сертификатов / ключей.

Безопасным способом определить, что ваш ключ / сертификат получен с устройства PKCS # 11, было бы использование поставщика SUN PKCS # 11. Однако это имеет тот недостаток, что вам потребуется указать путь к вашей собственной библиотеке PKCS # 11 либо статически (в файле java.security, где вы можете статически настраивать поставщиков), либо динамически запрашивать его в качестве пользовательского ввода.

Если использование поставщика PKCS # 11 в вашей ситуации вызывает слишком много проблем, я бы предложил реализовать диалоговое окно выбора сертификата, которое фильтрует подходящие сертификаты. Ограничение MSCAPI исходными сертификатами PKCS # 11 не приведет к немедленному повышению безопасности — возможно, есть веская причина, по которой у вашего пользователя установлены другие сертификаты / ключи (часто в виде файлов PKCS # 12). Вы должны только проверить (и помочь пользователю уже фильтровать сертификаты, соответствующие этому критерию), что сертификат / ключ, который был выбран в конечном итоге, соответствует вашим критериям: правильное использование ключа (например, цифровая подпись), разумное использование расширенного ключа, приемлемые или известные политики, присутствующие в сертификатах и т.д.

В ЕС мы медленно продвигаемся к понятию «Квалифицированных сертификатов на устройстве для создания защищенной подписи». Это означает, что сертификаты, которые поставляются на такое устройство (например, смарт-карту), будут содержать специальную политику, центрам сертификации запрещено использовать эти политики для любых других сертификатов, например сертификатов программного обеспечения. Таким образом, это эффективно позволило бы вам убедиться, что сертификат исходит от защищенного аппаратного устройства. Вы могли бы проверить, поддерживают ли задействованные сертификаты эту функцию. В этом документе ETSI перечислены соответствующие OID, которые вам придется искать.

Ответ №2:

В хранилищах ключей Java псевдоним ключа и сертификат должны быть связаны. По сути, запись закрытого ключа представляет собой цепочку закрытый ключ сертификат. Таким образом, сертификат всегда должен был поступать из хранилища ключей. Если сертификат получен от фактического токена, это, конечно, зависит от реализации хранилища ключей. Единственный способ проверить, действительно ли они были получены из токена, — это извлечь их другим методом (например, считав байты сертификата непосредственно из токена). Нет обратной ссылки на устройство хранения сертификатов, если это то, что вам нужно.

Конечно, имеет смысл проверить всю цепочку сертификатов вплоть до корневого сертификата. Если корневой сертификат меняется не часто, вы могли бы рассмотреть возможность сохранения сертификата или хэша поверх корневого сертификата в ресурсе, поставляемом вместе с вашим приложением, или распространения его в стандартном хранилище ключей Java.