Мне как-то удалось ее решить. 80% моих вопросов я решаю сам.........Я думаю, что это нормально.
В основном он состоит в создании двух экземпляров KeyStore
и двух экземпляров Provider
, каждый для каждого, один для пользовательских сертификатов, а другой для смарт-карт.
Создайте поставщика с libsoftokn.so
, например, первым config
в моем вопросе, и вставьте его. С KeyStore.Builder
и этим провайдером создайте KeyStore softKeyStore
. В этом хранилище ключей у вас есть все пользовательские сертификаты. Извлеките информацию об этих сертификатах и перечислите их в файле JTable
.
Вставьте смарт-карту до первой инициализации CryptoManager
. (В противном случае карта будет игнорироваться до перезапуска приложения.)
Инициализировать CryptoManager
. Вот несколько трюков, чтобы разорвать мертвую петлю AlreadyInitializedException
/NotInitializedException
:
У нас есть:
private static void initializeCryptoManager() throws Exception {
//load the NSS modules before creating the second keyStore.
if (cm == null) { //cm is of type CryptoManager
while (true) { //the trick.
try {
cm = CryptoManager.getInstance();
} catch (NotInitializedException e2) {
try {
InitializationValues iv = new InitializationValues(NSS_JSS_Utils.getFireFoxProfilePath());
//TEST
iv.installJSSProvider = false;
iv.removeSunProvider = false;
iv.initializeJavaOnly = false; //must be false, or native C error if no provider is created.
iv.cooperate = false;
iv.readOnly = true;
iv.noRootInit = true;
iv.configDir = NSS_JSS_Utils.getFireFoxProfilePath();
iv.noModDB = false;
// iv.noCertDB = false;
// CustomPasswordCallback cpc = new CustomPasswordCallback();
// iv.passwordCallback = cpc; //no passwordcallback needed here.
iv.forceOpen = false;
iv.PK11Reload = false;
CryptoManager.initialize(iv);
continue; // continue to getInstance.
} catch (KeyDatabaseException | CertDatabaseException | GeneralSecurityException e) {
Traza.error(e);
throw e;
} catch (AlreadyInitializedException e1) {
continue; //if is initialized, must go on to get cm.
}
}
break; //if nothing is catched, must break to end the loop.
}
}
}
И теперь мы можем сделать cm.getModules()
и module.getTokens()
, чтобы распознать карту. **Только когда карта вставлена, соответствующий модуль и его токен будут присутствовать. **
- Когда мы доберемся до токена карты, проверяем, нужен ли логин и зарегистрирован ли он. И мы должны исключить
InternalCryptoToken
и InternalKeyStorageToken
.
So:
if (!token.isInternalCryptoToken() && !token.isInternalKeyStorageToken()){ // If not Internal Crypto service, neither Firefox CA store
if (token.isPresent() ) { // when the card is inserted
if (!token.isLoggedIn()){ // Try to login. 3 times.
Traza.info("Reading the certificates from token " + token.getName() + ". Loggining... ");
while (UtilTarjetas.tries <= 3) {
try {
//TEST
token.setLoginMode(NSS_JSS_Utils.LOGIN_MODE_ONE_TIME);
token.login((PasswordCallback) new CustomPasswordCallback());
UtilTarjetas.prevTryFailed = false;
cm.setThreadToken(token);
break;
} catch (IncorrectPasswordException e){
UtilTarjetas.prevTryFailed = true;
UtilTarjetas.tries ++;
} catch (TokenException e) {
UtilTarjetas.prevTryFailed = true;
UtilTarjetas.tries ++;
}
}
// if tries > 3
if (UtilTarjetas.tries > 3) {
Traza.error("The token " + token.getName() + " is locked now. ");
throw new IOException("You have tries 3 times and now the card is locked. ");
}
}
if (token.isLoggedIn()) {
....
}
Когда токен войдет в систему, выполните сценарий оболочки с Runtime.getRuntime().exec(command)
, чтобы использовать modutil
, поставляемый с NSS.
В шелле это так:
modutil -dbdir /your/firefox/profile/dir -rawlist
Эта команда показывает информацию, содержащуюся в secmod.db
, в удобочитаемом формате.
name="NSS Internal PKCS #11 Module" parameters="configdir=/home/easternfox/.mozilla/firefox/5yasix1g.default-1475600224376 certPrefix= keyPrefix= secmod=secmod.db flags=readOnly " NSS="trustOrder=75 cipherOrder=100 slotParams={0x00000001=[slotFlags=RSA,RC4,RC2,DES,DH,SHA1,MD5,MD2,SSL,TLS,AES,SHA256,SHA512,Camellia,SEED,RANDOM askpw=any timeout=30 ] 0x00000002=[ askpw=any timeout=0 ] } Flags=internal,critical"
library=/usr/lib/libpkcs11-dnie.so name="DNIe NEW"
library=/usr/local/lib/libbit4ipki.so name="Izenpe local" NSS=" slotParams={0x00000000=[ askpw=any timeout=0 ] } "
Таким образом, вы можете проанализировать вывод и получить местоположение библиотеки в строке, где находятся ваши module.getName()
. Мы можем использовать StringTokenizer
.
//divide the line into strings with "=".
StringTokenizer tz = new StringTokenizer(line, "=");
//get the first part, "library".
String token = tz.nextToken();
//get the second part, "/usr/local/lib/libbit4ipki.so name"
token = tz.nextToken();
....
- Затем, используя путь к файлу драйвера
.so
, создайте строку config
для загрузки другого поставщика.
Мы будем иметь:
String config = "name=\"" + moduleName + "\"\n" + "library=" + libPath;
moduleName
лучше экранировать символом "\", потому что он обычно содержит пробелы. libPath
следует экранировать, если нужны пробелы. Лучше без пробелов.
Вставьте этого провайдера и создайте cardKeyStore
с тем же провайдером.
Provider p = new SunPKCS11(new ByteArrayInputStream(config.getBytes()));
Security.insertProviderAt(p, 1);
KeyStore.Builder builder = null;
builder = KeyStore.Builder.newInstance("PKCS11", p,
new KeyStore.CallbackHandlerProtection(new UtilTarjetas().new CustomCallbackHandler()));
cardKeyStore = builder.getKeyStore();
Перечислите псевдонимы сертификатов, которые мы получаем от cardKeyStore
в том же JTable
, который мы использовали выше, вместе с сертификатами softKeyStore
.
Когда пользователь выбирает строку в JTable
, получает выбранный псевдоним и сохраняет его в статическом поле.
Когда нам нужно хранилище ключей для создания KeyManagerFactory
и X509KeyManager
для связи SSL, со статическим alias
мы ищем его в softKeyStore
, а затем cardKeyStore
.
Нравиться:
if (softKeyStore.containsAlias(alias)) {
return softKeyStore;
} else if (cardKeyStore.containsAlias(alias)) {
return cardKeyStore;
}
- SSL-рукопожатие, отправка сообщений, получение, подписание и т. д.
person
WesternGun
schedule
23.11.2016