iText: проблема с паролем при внедрении цифровой подписи для файла PDF на сервере
Новый пользователь для iText пытается получить пример кода, адаптированный из образца 3.1 и примера кода 3.2, в https://itextpdf.com/book/digitalsignatures
Я включил фрагменты кода ниже FYI.
У меня был хостинг-провайдер создать .pfx
файл из сертификата GlobalSign (они не предоставляют .p12
файл). Они выпустили следующую команду Linux:
# openssl pkcs12 -export -out cert.pfx -inkey www.mydomain.com.key
-in ../certs/www.mydomain.com.crt -certfile ../certs/ca-bundle.crt
где ca-bundle.crt
исходит от GlobalSign. Чтобы получить .p12
Я просто скопировал .pfx
файл в новый файл с .p12
расширение. Из того, что я вижу в Интернете, люди делали это раньше (не связано с iText) и добились успеха, так как .pfx
файл и .p12
файлы являются двоичными эквивалентами.
Чтобы проверить, можно набрать в приглашении linux:
openssl pkcs12 -info -in /path/to/file/cert.pfx
Затем он запрашивает пароль для импорта, а пароль отсутствует, поэтому просто нажмите клавишу ВВОД, а затем - частную фразу-пароль, которую я ввожу (например, myPrivateCertPassword
), а затем отображаются мой личный сертификат, открытый сертификат GlobalSign и мой закрытый ключ.
Вот где я запутался. Нет пароля для импорта, поэтому я попробовал следующие попытки в iText (как показано в фрагментах ниже):
ks.load(new FileInputStream(CONSTANTS.CERTIFICATE_PATH), null);
ks.load(new FileInputStream(CONSTANTS.CERTIFICATE_PATH), "".toCharArray());
ни один не работает. Первый дает ошибку во время выполнения:
java.io.IOException: PKCS12 key store mac invalid - wrong password or corrupted file.
а второй дает ошибку времени выполнения:
java.lang.NoClassDefFoundError : org/bouncycastle/cert/X509CertificateHolder
Есть идеи, что может быть не так?
Где именно пароль, используемый в ks.load()
Строка кода пришла от (GlobalSign "сервер хостинг компании" я "). Это называется export key
когда я запускаю указанную выше команду экспорта?
Заранее спасибо за любые комментарии.
-------- фрагменты кода следуют ---------
public static final char[] PASS = "myPrivateCertPassword".toCharArray();
public static final String CERTIFICATE_PATH = "/path/to/file/cert.p12";
В основном ():
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
KeyStore ks = KeyStore.getInstance("pkcs12", provider.getName());
ks.load(new FileInputStream(CONSTANTS.CERTIFICATE_PATH), null);
// ks.load(new FileInputStream(CONSTANTS.CERTIFICATE_PATH), "".toCharArray()); // this also fails
String alias = (String)ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, CONSTANTS.PASS);
Certificate[] chain = ks.getCertificateChain(alias);
sign(userFile, userFile_signed, chain, pk, DigestAlgorithms.SHA256,
provider.getName(),CryptoStandard.CMS, "Test", "Ghent", null, null, null, 0);
Вне основного ():
public void sign(
String src,
String dest,
Certificate[] chain,
PrivateKey pk,
String digestAlgorithm,
String provider,
CryptoStandard subfilter,
String reason,
String location,
Collection<CrlClient> crlList,
OcspClient ocspClient, TSAClient tsaClient,
int estimatedSize)
throws GeneralSecurityException, IOException, DocumentException {
// Creating the reader and the stamper
PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
// Creating the appearance
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
// Creating the signature
ExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
ExternalDigest digest = new BouncyCastleDigest();
MakeSignature.signDetached(appearance, digest, pks, chain,
crlList, ocspClient, tsaClient, estimatedSize, subfilter);
}
ОБНОВЛЕНИЕ 1:
Я создал новый файл cert.pfx, выполнив экспорт, как описано выше, но на этот раз я ввел "пароль экспорта", так как exportPassword
, который я вставил как:
ks.load(new FileInputStream(CONSTANTS.CERTIFICATE_PATH), "exportPassword".toCharArray());
но это дает новую ошибку времени выполнения:
java.io.IOException: exception decrypting data - java.security.InvalidKeyException: Illegal key size
Я все ближе?
ОБНОВЛЕНИЕ 2:
Я установил JCE на комментарий Бруно, и теперь я получаю эту ошибку:
java.lang.NoClassDefFoundError : org/bouncycastle/tsp/TimeStampTokenInfo
ОБНОВЛЕНИЕ 3:
Мне удалось устранить вышеуказанную ошибку, также добавив bcpkix-jdk15on-149.jar из www.bouncycastle.org в каталог /lib и добавив следующее в java-программу:
import org.bouncycastle.jce.provider.BouncyCastleProvider; // this was already there
import org.bouncycastle.tsp.TimeStampTokenInfo; // this is new and fixed the above error
Теперь я вижу цифровую подпись!
ОБНОВЛЕНИЕ 4:
Для тех, кто заинтересован, смотрите мой пост здесь: iText: какие типы сертификатов люди используют для автоматизации подписи PDF в Linux?