Подпишите PDF-файл с помощью iTEXT Java с сертификатом в облаке без контейнера CMS (голые данные)JAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Подпишите PDF-файл с помощью iTEXT Java с сертификатом в облаке без контейнера CMS (голые данные)

Сообщение Anonymous »

Я реализую процесс цифровой подписи PDF с помощью iText 7 на Java. Рабочий процесс требует от меня:
  • Подготовить PDF-файл к подписи: создать видимое поле подписи и сгенерировать хеш содержимого PDF-файла. Этот хэш будет отправлен в облачную службу подписи.
  • Получить данные подписи: служба возвращает JSON, содержащий подписанный хеш (signedContent). , сертификат (кодированныйX509) и другую информацию.
  • Финализация подписи: введите данные подписи в созданное ранее поле.
анализируя подобные сомнения, я пришел к такому решению, которое считаю наиболее подходящим.

Код: Выделить всё

private static byte[] emptySignature(String src, String dest, String fieldname, Certificate[] chain)
throws IOException, GeneralSecurityException
{
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());

PdfSignatureAppearance appearance = signer.getSignatureAppearance();
appearance.setPageRect(new Rectangle(100, 500, 200, 100));
appearance.setPageNumber(1);
appearance.setCertificate(chain[0]);
appearance.setReason("For test");
appearance.setLocation("HKSAR");
signer.setFieldName(fieldname);

PreSignatureContainer external = new PreSignatureContainer(PdfName.Adobe_PPKLite, PdfName.Adbe_pkcs7_detached);
signer.signExternalContainer(external, 8192);

return external.getHash();
}

public static class PreSignatureContainer implements IExternalSignatureContainer {
private final PdfDictionary sigDic;
private byte[] hash;

public PreSignatureContainer(PdfName filter, PdfName subFilter) {
sigDic = new PdfDictionary();
sigDic.put(PdfName.Filter, filter);
sigDic.put(PdfName.SubFilter, subFilter);
}

@Override
public byte[] sign(InputStream data) throws GeneralSecurityException {
String hashAlgorithm = "SHA256";
BouncyCastleDigest digest = new BouncyCastleDigest();
X509Certificate certificate = null;
Certificate[] certs = null;

try{
certificate = getCertificate("cert");
certs = new Certificate[]{certificate};
} catch (Exception ex){
ex.printStackTrace();
}

try {
byte[] hash = DigestAlgorithms.digest(data, digest.getMessageDigest(hashAlgorithm));
PdfPKCS7 pkcs7 = new PdfPKCS7(null,certs , "SHA-256", null, digest, false);
byte[] sh = pkcs7.getAuthenticatedAttributeBytes(hash,PdfSigner.CryptoStandard.CMS, null, null);
this.hash = sh;
} catch (IOException e) {
throw new GeneralSecurityException("PreSignatureContainer signing exception", e);
}

return new byte[0];
}

@Override
public void modifySigningDictionary(PdfDictionary signDic) {
signDic.putAll(sigDic);
}

public byte[] getHash() {
return hash;
}

byte[] signatureBytes = THE_RETRIEVED_SIGNATURE_BYTES;
byte[] certificateBytes = THE_RETRIEVED_CERTIFICATE_BYTES;
Ответ API в формате JSON

Код: Выделить всё

{   "data": {      "requestId": "01JEE2TDRMZAV8GZTMQPHGTMKJ",      "executionStatus": {         "currentStatus": "COMPLETED-WITH-SIGNATURE",         "requestTimestamp": "2024-12-06T13:33:49.204Z",         "executionTimestamp": "2024-12-06T13:33:49.369Z"      },      "subjectIdentification": {         "identificationKey": "104699xxx",         "identificationType": "CPF"      },      "certificateInformation": {         "serialNumber": "1AADB23286C489B4",         "issuerName": "C=BR\nO=ICP-Brasil\nOU=Secretaria da Receita Federal do Brasil - RFB\nCN=AC VALID RFB v5",         "validity": {            "notBefore": "Oct 28 21:23:44 2023 GMT",            "notAfter": "Oct 26 21:23:44 2028 GMT"          },         "subjectName": "C=BR\nO=ICP-Brasil\nOU=Secretaria da Receita Federal do Brasil - RFB\nOU=RFB e-CPF A3\nOU=AC VALID RFB V5\nOU=AR CFM\nOU=Presencial\nOU=33583550000130\nCN=GESxxxxx:1046998xxx",         "encodedX509": "-----BEGIN CERTIFICATE-----\nMIIHuzCCBaOgAwIBAgIIGq2yMobEibQwDQYJKoZIhvcNAQELBQAwdDELMAkGA1UE\nBhMCQlIxEzARBgNVBAoTCklDUC1CcmFzaWwxNjA0BgNVBAsTLVNlY3JldGFyaWEg\nZGEgUmVjZWl0YSBGZWRlcmFsIGRvIEJyYXNpbCAtIFJGQjEYMBYGA1UEAxMPQUMg\nVkFMSUQgUkZCIHY1MB4XDTIzMTAyODIxMjM0NFoXDTI4MTAyNjIxMjM0NFowgfkx\nCzAJBgNVBAYTAkJSMRMwEQYDVQQKEwpJQ1AtQnJhc2lsMTYwNAYDVQQLEy1TZWNy\nZXRhcmlhIGRhIFJlY2VpdGEgRmVkZXJhbCBkbyBCcmFzaWwgLSBSRkIxFTATBgNV\nBAsTDFJGQiBlLUNQRiBBMzEYMBYGA1UECxMPQUMgVkFMSUQgUkZCIFY1MQ8wDQYD\nVQQLEwZBUiBDRk0xEzARBgNVBAsTClByZXNlbmNpYWwxFzAVBgNVBAsTDjMzNTgz\nNTUwMDAwMTMwMS0wKwYDVQQDEyRHRVNJQU5FIERBIFNJTFZBIExPVVJFRE86MTA0\nNjk5ODE3MDkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDdHA8yOrnU\n39JvVhJyw9HYtBPwEGFUsUEIMfYRi9inBWDD5KDVu43LXQQy0iliwr4ov2qHy66y\nMAFaH/jqLbqIfXYDlM7IJOMUnoRgYaO7yFpjnJKmje7yTLORYA+ZE7cdwb8RfpcE\n+CtNtmEhzoabP1bUNQUISujL/3KXDSYx7AJxHWoH9ms+RBHmUOH/qFggPK6EYA6o\nylQFxseDAsZM2bM8dyP+b3us0REOZMSkV+3yCeP8QsFlmg117Gq8Sva2pW7MeNGf\ndMYOButXqzYMPnHKI7BeZpEUvtnWpIcnxECsYr6yooWsTSi8KK5Jw+eETj7RXPJj\nbijoxfvKyqyHAgMBAAGjggLJMIICxTCBnAYIKwYBBQUHAQEEgY8wgYwwVQYIKwYB\nBQUHMAKGSWh0dHA6Ly9pY3AtYnJhc2lsLnZhbGlkY2VydGlmaWNhZG9yYS5jb20u\nYnIvYWMtdmFsaWRyZmIvYWMtdmFsaWRyZmJ2NS5wN2IwMwYIKwYBBQUHMAGGJ2h0\ndHA6Ly9vY3NwdjUudmFsaWRjZXJ0aWZpY2Fkb3JhLmNvbS5icjAJBgNVHRMEAjAA\nMB8GA1UdIwQYMBaAFFPLpeR1UJlALL5bFUXJvsswqonFMHAGA1UdIARpMGcwZQYG\nYEwBAgMkMFswWQYIKwYBBQUHAgEWTWh0dHA6Ly9pY3AtYnJhc2lsLnZhbGlkY2Vy\ndGlmaWNhZG9yYS5jb20uYnIvYWMtdmFsaWRyZmIvZHBjLWFjLXZhbGlkcmZidjUu\ncGRmMIG2BgNVHR8Ega4wgaswU6BRoE+GTWh0dHA6Ly9pY3AtYnJhc2lsLnZhbGlk\nY2VydGlmaWNhZG9yYS5jb20uYnIvYWMtdmFsaWRyZmIvbGNyLWFjLXZhbGlkcmZi\ndjUuY3JsMFSgUqBQhk5odHRwOi8vaWNwLWJyYXNpbDIudmFsaWRjZXJ0aWZpY2Fk\nb3JhLmNvbS5ici9hYy12YWxpZHJmYi9sY3ItYWMtdmFsaWRyZmJ2NS5jcmwwDgYD\nVR0PAQH/BAQDAgXgMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDCBnQYD\nVR0RBIGVMIGSgR1nZXNpYW5lQGdlc2lhbmVsb3VyZWRvLmNvbS5icqA4BgVgTAED\nAaAvBC0wMjAxMTk4NDEwNDY5OTgxNzA5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw\nMDCgFwYFYEwBAwagDgQMMDAwMDAwMDAwMDAwoB4GBWBMAQMFoBUEEzAwMDAwMDAw\nMDAwMDAwMDAwMDAwDQYJKoZIhvcNAQELBQADggIBADZj9JIDrq62FpHCF6pE/up9\nWtNrFJysiRfR7IUJKsj2EzL+HpDRA+Dr0T7rI7VDksKwBr1m/mVxKtC7H/AUa6t+\n3zXfH1Ryj1HoPBYNNt2KPFcfTHjPo9ah/bmDv3aA5pfpRAZrMomfD5qzQujbIH0U\nbH+Z5PNmC4vuZhU3aI334u1ztuhiwMNpBnRvtQOwD+/dQACiTktE2xj667c09KRZ\neNxT1ByAMib1JJt175ovF+l1MT3FA4h0PSiK7iNyFbhewExu9CmU2ixi7mk00qUC\nxSjNvLJuHayelxfpeOGkJ+Q2Zg7HRfu7zvD1F+6WbJmGzPiS8/5xB6ivpHD9C4Vv\nkq5hKIiGiJBbGiNZGfNBUzHocKHxYN9Qxgj/XLzjJEkSBhhPESVVuTBqkAYISuwv\nsyqZe1H+mM14ifvsdqq8IJzTl9Ii6JvvbZBFXLelu2xXlas00yE4muZV/nnFOnNR\nFjPbscq+fHOREPbZIALeT0EVUjDnID1325kLGQx9cRE2j3GswBRvuQpbZZLqfcpc\nh7miq/rQFaav3t1tQjEQ2g/atqgSBHqmQZnh4msIHqrW5WFM9rE/6tanDWQ5Vd5H\nEuykLJm7AvXKQnNhZhO6kQ49SFN1+/AXxhdqeCdzBWpg/SiELAdtYheXJLDC0gZW\n41LnKzM8WzI3NPwXC9Nq\n-----END CERTIFICATE-----\n",         "fingerprint256": "EE:9E:F4:78:9D:93:4D:2B:77:AC:08:FE:5D:36:C4:27:6A:EB:73:C1:C2:C0:69:FA:BA:94:7D:51:CA:5F:B5:54",         "subjectAlternatives": "email:gexxx@gesxnxxxxx.com.br"      },      "signatures": [         {            "signatureId": "01JEE2TDRMBVMPHKM8S2AWQ2S0",            "contentId": "1",            "contentDigest": "NgiGYmzUlAf0xLNDTdQQGP7XdPzrNDjgClsgA3fcpVA=",            "contentDescription": "DOCUMENTO_PDF",            "signedContent": "vyBnlyq4Plv4lUkaSwpUUmIjGXKZaY6yYnjUmiZA4UH0ypTLF7zgoi+O2i87kVyjMiO/mZ1JcOxIQpepD8dgFyWBA8Sn8g4IrTFfIe8dYQPy8v6zqZyYTXg+Rywupd6Qqo4wWEyay0p/7tnTVSCTA1YJLsVuvOAWc291gG6jdy0w39H+3dBYl1dAhtz6qExXXX/1eAgVDBw65UfvVzAU6YTM08G6+SrrUdTJgwToILACtW8aFZrIzK4kvXqhHBrF1+hL/85lFstEoNEeXISwR11WBc2Ek9f/YV4yPu9JVmHCUd/QpTyWJ5avnIzMuYR+UJlRNfxZaTYbKAEYlnGeiw==",            "signatureTimestamp": "2024-12-06T13:33:49.369Z",            "extended": {}         }      ]   }}
У меня вопрос о том, как сгенерировать контейнер CMS, используя данные из этого JSON, которые я получил в качестве ответа от API. Я не прикрепил никаких PDF-файлов, поскольку все созданные мной файлы не являются полными, поскольку мне еще не удалось создать контейнер CMS с этими данными.
Я ценю любую помощь.
Я ценю любую помощь.
Я ценю любую помощь. p>
Обновление 1
Сразу после того, как я опубликовал вопрос, я смог его подписать.
Код выглядел так.
Подготовка контейнера

Код: Выделить всё

private static String emptySignature(String src, String dest, String fieldname)
throws IOException, GeneralSecurityException {
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());

com.itextpdf.signatures.PdfSignatureAppearance appearance = signer.getSignatureAppearance();
appearance.setPageRect(new Rectangle(0, 0, 0, 0));
appearance.setPageNumber(1);
appearance.setReason("For test");
appearance.setLocation("HKSAR");
signer.setFieldName(fieldname);

PreSignatureContainer external = new PreSignatureContainer(PdfName.Adobe_PPKLite, PdfName.Adbe_pkcs7_detached);
signer.signExternalContainer(external, 8192);

return Base64.getEncoder().encodeToString(external.getHash());
}

public static class PreSignatureContainer implements IExternalSignatureContainer {

private final PdfDictionary sigDic;
private byte[] hash;

public PreSignatureContainer(PdfName filter, PdfName subFilter) {
sigDic = new PdfDictionary();
sigDic.put(PdfName.Filter, filter);
sigDic.put(PdfName.SubFilter, subFilter);
}

@Override
public byte[] sign(InputStream data) throws GeneralSecurityException {
String hashAlgorithm = "SHA256";
BouncyCastleDigest digest = new BouncyCastleDigest();
try {
byte[] hash = DigestAlgorithms.digest(data, digest.getMessageDigest(hashAlgorithm));
this.hash = hash;
} catch (IOException e) {
throw new GeneralSecurityException("PreSignatureContainer signing exception", e);
}
return new byte[0];
}

@Override
public void modifySigningDictionary(PdfDictionary signDic) {
signDic.putAll(sigDic);
}

public byte[] getHash() {
return hash;
}
}
включение подписи в подготовленный Контейнер

Код: Выделить всё

public String getSignedContent(String tempPdfPath, JSONObject jsonObject) throws IOException {
PdfReader reader = null;
try {
// Obtém o valor de "signedContent"  diretamente do JSON
String signedContentBase64 = jsonObject
.getJSONObject("data")
.getJSONArray("signatures")
.getJSONObject(0) // Primeiro (e único) objeto
.getString("signedContent");

// Decodificar o conteúdo assinado de Base64
byte[] signedContent = Base64.getDecoder().decode(signedContentBase64);

// Certificado do JSON para validar a assinatura
String encodedCertificate = jsonObject
.getJSONObject("data")
.getJSONObject("certificateInformation")
.getString("encodedX509");

byte[] certificateBytes = Base64.getDecoder().decode(
encodedCertificate.replace("-----BEGIN CERTIFICATE-----", "")
.replace("-----END CERTIFICATE-----", "")
.replace("\n", "")
);

// Criar um objeto X509Certificate a partir dos dados do certificado
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
X509Certificate certificate;
try (ByteArrayInputStream certInputStream = new ByteArrayInputStream(certificateBytes)) {
certificate = (X509Certificate) certFactory.generateCertificate(certInputStream);
}

reader = new PdfReader(tempPdfPath);
byte[] signedPdfBytes;

try (ByteArrayOutputStream signedPdfOutputStream = new ByteArrayOutputStream()) {
// Criar um PdfSigner para o PDF assinado
PdfSigner signer = new PdfSigner(reader, signedPdfOutputStream, new StampingProperties());

// Criar um contêiner PKCS7
PdfPKCS7 pkcs7 = new PdfPKCS7(null, new X509Certificate[]{certificate}, "SHA256", null, new BouncyCastleDigest(), false);
pkcs7.setExternalDigest(signedContent, null, "RSA");

// Obter o pacote PKCS7
byte[] pkcs7Bytes = pkcs7.getEncodedPKCS7(null, PdfSigner.CryptoStandard.CMS, null, null, null);

// Usar signDeferred para assinar o campo de assinatura existente
// Criar um contêiner de assinatura que implemente IExternalSignatureContainer
IExternalSignatureContainer external = new MyExternalSignatureContainer(pkcs7Bytes);

String fieldName = "Signature1"; // Nome do campo de assinatura existente
PdfSigner.signDeferred(signer.getDocument(), fieldName, signedPdfOutputStream, external);

// Obter os bytes do PDF assinado
signedPdfBytes = signedPdfOutputStream.toByteArray();
}

// Codificar o PDF assinado em Base64 e retornar
return Base64.getEncoder().encodeToString(signedPdfBytes);
} catch (Exception e) {
System.err.println("Erro ao processar o JSON ou assinar o PDF: " + e.getMessage());
return null;  // Retorna nulo em caso de erro
} finally {
if (reader != null) {
reader.close();
}
// Apagar o arquivo temporário
File tempFile = new File(tempPdfPath);
if (tempFile.exists()) {
tempFile.delete();
}
}
}

private static class MyExternalSignatureContainer implements IExternalSignatureContainer {

private final byte[] pkcs7Bytes;

public MyExternalSignatureContainer(byte[] pkcs7Bytes) {
this.pkcs7Bytes = pkcs7Bytes;
}

@Override
public byte[] sign(InputStream data) {
return pkcs7Bytes;
}

@Override
public void modifySigningDictionary(PdfDictionary signDic) {
// Implementação do método de modificação do dicionário de assinatura
}
}
JSON, который можно получить из данных пользовательского сертификата Поможет ли эта информация перед подписанием каким-либо образом?

Код: Выделить всё

{
"data": {

"credentialId": "string",

"executionStatus": {
"currentStatus": "PENDING_SIGNATURE",
"requestTimestamp": "2019-08-24T14:15:22Z",
"executionTimestamp": "2019-08-24T14:15:22Z"
},

"subjectIdentification": {
"identificationKey": "string",
"identificationType": "CPF"
},

"certificateInformation": {

"serialNumber": "string",
"issuerName": "string",

"validity": {
"notBefore": "1977-01-01T00:00:00Z",
"notAfter": "1977-01-01T00:00:00Z"
},

"subjectName": "string",
"encodedX509": "string",
"fingerprint256": "string"
}
}
}
На некоторых машинах при открытии PDF-файла отображается это предупреждение.
На некоторых машинах при открытии PDF-файла отображается это предупреждение.
"Личность подписавшего неизвестна, поскольку она не была включена в ваш список доверенных лиц, и ни один из родительских сертификатов не является доверенным сертификатом"
здесь — это вывод PDFSIG PDF-файла, который отображается без какого-либо предупреждения.

Код: Выделить всё

NSS_Init failed: security library: bad database.
Информация о цифровой подписи: Signed.pdf
Подпись №1:
  • Имя поля подписи: 25e8a269 -03a8-4685-ae26-3e746805c0f3@validpsc
  • Общее имя сертификата подписавшего: GESIANE DA SILVA LOUREDO:10469981709
  • Полное отличительное имя подписавшего: CN=GESIANE DA SILVA LOUREDO:10469981709,OU=33583550000130,OU=Presencial,OU=AR CFM,OU=AC VALID RFB V5,OU= RFB e-CPF A3,OU=Secretaria da Receita Federal do Brasil - RFB,O=ICP-Brasil,C=BR
  • Время подписания: 14 ноября 2023 г., 06:03:11
  • Алгоритм хеширования подписи: SHA-256
  • Тип подписи: ETSI.CAdES.detached
  • Диапазоны подписей: [0–1223818], [1327786–1329701]
  • Всего подписанных документов
  • Проверка подписи: подпись действительна .
  • Проверка сертификата: эмитент сертификата не является доверенным.
и вот результат PDF-файл, подписанный кодом обновления 1

Код: Выделить всё

NSS_Init failed: security library: bad database.
Информация о цифровой подписи: laudo_signed.pdf
Подпись №1:
  • Имя поля подписи: Signature1
  • Общее имя сертификата подписавшего: GESIANE DA SILVA LOUREDO: 10469981709
  • Полное отличительное имя подписавшего: CN=GESIANE DA SILVA LOUREDO:10469981709,OU=33583550000130,OU=Presencial,OU=AR CFM,OU=AC VALID RFB V5,OU=RFB e-CPF A3,OU=Secretaria da Receita Federal do Brasil - RFB,O= МСП-Бразилия, C=BR
  • Время подписания: 9 декабря 2024 г., 10:34:35
  • Хеш-алгоритм подписи: SHA-256
  • Тип подписи: adbe. pkcs7.detached
  • Диапазоны знаков: [0–141], [16527–73936]
  • Всего подписанных документов
  • Проверка подписи: подпись действительна.
  • Проверка сертификата: издатель сертификата неизвестен.
Я отправляю оба PDF-файла на проверку
PDF создан с использованием кода обновления 1
Нет Предупреждение PDF
Обновить 2
Это будет полный json при вызове для получения учетных данных пользователя. Этот вызов можно сделать перед подписанием, чтобы мы могли получить доступ к сертификату. Как можно было бы включить всю цепочку сертификатов, чтобы сделать сертификат полностью действительным? "data": {
"credentialId": "01JERJKX21PRNP0VN8VVV1C6WC",
"currentTimestamp": "2024-12-10T15: 23: 41.101Z",< "expireTimestamp": "2024-12-11T03:23: 40.979Z",
"executionsStatus": {
"currentStatus": "PENDING_SIGNATURE",
"requestTimestamp": "2024-12-10T15: 23: 40.979Z"
} ,
"subjectIdentification": {
"identificationKey": "xxxxxxxxxxxxx",
"identificationType": "CPF"
},
"certificateInformation": {
"serialNumber": "51AD3A27FFEA6DB6",
"issuerName": "C=BR\nO =ICP-Бразилия\nOU=Секретариат федеральных доходов Бразилии - RFB\nCN=AC VALID RFB v5",
"validity": {
"notBefore": "10 декабря 12:49:47 2024 по Гринвичу",
"notAfter": "10 декабря 12:49:47 2028 по Гринвичу"
},
"subjectName" : "C=BR\nO=ICP-Brasil\nOU=Секретариат федеральных доходов Бразилии - RFB\nOU=RFB e-CPF A3\nOU=AC VALID RFB V5\nOU=AR VALID CD\nOU=Видеоконференция\nOU=14121957000109\nCN=: ",
"encodedX509": "-----НАЧАТЬ СЕРТИФИКАТ----- \ nMIIH3zCCBcegAwIBAgIIUa06J //qbbYwDQYJKoZIhvcNAQELBQAwdDELMAkGA1UE\nBhMCQlIxEzARBgNVBAoTCklDUC1CcmFzaWwxNjA0BgNVB AsTLVNlY3JldGFyaWEg\nZGEgUmVjZWl0YSBGZWRlcmFsIGRvIEJyYXNpbCAtIFJGQjEYMBYGA1UEAxMPQUMg\ nVkFMSUQgUkZCIHY1MB4XDTI0MTIxMDEyNDk0N1oXDTI4MTIxMDEyNDk0N1owggEO\nMQswCQYDVQQGEwJCUjE TMBEGA1UEChMKSUNQLUJyYXNpbDE2MDQGA1UECxMtU2Vj\ncmV0YXJpYSBkYSBSZWNlaXRhIEZlZGVyYWwgZG8g QnJhc2lsIC0gUkZCMRUwEwYD\nVQQLEwxSRkIgZS1DUEYgQTMxGDAWBgNVBAsTD0FDIFZBTelEIFJGQiBWNTEU MBIG\nA1UECxMLQVIgVkFMSUQgQ0QxGTAXBgNVBAsTEFZpZGVvY29uZmVyZW5jaWExFzAV\nBgNVBAsTDjE0MT IxOTU3MDAwMTA5MTcwNQYDVQQDEy5HQUJSSUVMIFJFR0lOQVRU\nTyBERSBTT1VaQSBNRU5FWkVTOjE0NTM1MT g1NzYwMIIBijANBgkqhkiG9w0BAQEF\nAAOCAQ8AMIIBCgKCAQEAulPYtW3LdO36C7Y+DEJR60YjqK1gP71Mpy5 rm2nf3iAN\nMJNjHi+qXCJOflz4fRrbpUvBUbScf72a+/z9BtfpI7Gkj4E4xaRPU49oJ4aKhIBH\nVCoTBRnw2 LNINKkGvZRuoetZK/Chqd3THbr5tXifWuakqY08JgN1C3X06FrvE3HW\ngegWi2Q7usWrC8M3nYpE/ENVX6Nh1 1+7eHT80FSCzRJQF6902hnTGGyrWFmfeCsC\n5jZS4HgroqbPAOHJ0PLxUYweW+hUxbMIjGneBI38cLEhiX3KP sAyRTpI2Rykhnr6\nTNM91BmnXrtMDutkeBou4GXmo1xOglxRmlUIJbOfKQIDAQABo4IC1zCCATMwgZwG\nCCsG AQUFBwEBBIGPMIGMMFUGCCsGAQUFBzAChklodHRwOi8vaWNwLWJyYXNpbC52\nYWxpZGNlcnRpZmljYWRvcmEu Y29tLmJyL2FjLXZhbGlkcmZiL2FjLXZhbGlkcmZi\ndjUucDdiMDMGCCsGAQUFBzABhidodHRwOi8vb2NzcHY1 LnZhbGlkY2VydGlmaWNh\nZG9yYS5jb20uYnIwCQYDVR0TBAIwADafBgNVHSMEGDAWgBRTy6XkdVCZQCy+WxVF \nyb7LMKqJxTBwBgNVHSAEaTBnMGUGBmBMAQIDJDBbMFkGCCsGAQUFBwIBFk1odHRw\nOi8vaWNwLWJyYXNpbC5 2YWxpZGNlcnRpZmljYWRvcmEuY29tLmJyL2FjLXZhbGlk\ncmZiL2RwYy1hYy12YWxpZHJmYnY1LnBkZjCBtgY DVR0fBIGuMIGrMFOgUaBPhk1o\ndHRwOi8vaWNwLWJyYXNpbC52YWxpZGNlcnRpZmljYWRvcmEuY29tLmJyL2F jLXZh\nbGlkcmZiL2xjci1hYy12YWxpZHJmYnY1LmNybDBUoFKgUIZOaHR0cDovL2ljcC1i\ncmFzaWwyLnZhb GlkY2VydGlmaWNhZG9yYS5jb20uYnIvYWMtdmFsaWRyZmIvbGNy\nLWFjLXZhbGlkcmZidjUuY3JsMA4GA1UdDw EB/wQEAwIF4DAdBgNVHSUEFjAUBggr\nBgEFBQcDAgYIKwYBBQUHAwQwgasGA1UdEQSBozCBoIEmZ2FicmllbC 5tZW5lemVz\nQG1lZGlsYWJzaXN0ZW1hcy5jb20uYnKgPQYFYEwBAwGgNAQyMTcwMzE5OTcxNDUz\nNTE4NTc2 MDAwMDAwMDAwMDAwMDAwMDAwMjc2Mzc2NjU0U1NQUkqgFwYFYEwBAwag\nDgQMMDAwMDAwMDAwMDAwoB4GBWBM AQMFoBUEEzAwMDAwMDAwMDAwMDAwMDAwMDAw\nDQYJKoZIhvcNAQELBQADggIBABn/VN6HAsGmWTSKAesgr1xXQ jfmxi4aLhIs+24K\nNsBTqQv4XfUg7Rjq52SIcz9gSYcISLUACo0bz1HcR3hfEu8UA0aiEROHba6tLemc\nyZA KXyCtskzD4cWoP3pGxXDFINpwCiCK54yGUki6T5PPOIgVZkJDxYevEW4aU4YB\nkYPXNa6ub+HSuiZkGa4A4PL xcZfkL7GGJ3WpOzT8i6mSas3XLbybtLsG6BbiHiGE\nVXxNwTpMPEeDMev2eSYJLoa0Amrkd9yQ9kCli3Vvjgh mYyIk4tStDjjXrP2XMOCY\nNfNqTU10H5Yofz82AIRqMFiHswhp6m6W1nJn1V+nSlocX7NpIXWhdXJsZTq6s1kG \nDZUsR36b7a6/VC7k9fs2lbAs7hmqxL1ASUqfzN90RQ8NhFD6qS/UDAUNz1txMCuT\nAwmZKtx1PjxVypGh+6 b5zOjdaS1V6wXyQvPKcogk7DoKyMBkGjkbWTRZaPIgqNVM\nV8/BeijdPq1H/VvQzJXWUAk6S0MkX1puDjiZ+VR BTLTxpXmkyggV6Wy+EUL43obN\nsD3YvCsXldlnx5TZyz6lyqOAFG+1VDqO/6lju0kZ/d/CHJLBFg76YwFEuPP qr2O6\nJ4wx2ROymyn0pyXrxx6aEKmgpQu5HCk8f80zB26mftFUnPdq/8qAtMv6QGk4cv34\nd9IK\n-----END СЕРТИФИКАТ-----\n",
"fingerprint256": "36:F6:BA:18:88:CF:58:18:51:F6:21:DF:67:B4:A8:8A :E5:E5:69:FA:88:18:04:FB:3D:CA:8E:38:BA:31:DA:C8",
"subjectAlternatives": "электронная почта: xxx@yyy.com.br"
}
}

Обновление 3:< /strong>
Мне удалось реализовать включение цепочки сертификатов согласно вашему предложению. Вот код, который я использовал для создания цепочки сертификатов из расширения AIA и включения ее в подпись PDF.
Создание цепочки сертификатов:

Код: Выделить всё

// Method to build the certificate chain
private static List buildCertificateChain(X509Certificate certificate) throws Exception {
List chain;
X509Certificate currentCert = certificate;
// Extract the AIA extension
byte[] aiaExtension = currentCert.getExtensionValue("1.3.6.1.5.5.7.1.1"); // AIA OID
// Extract the CA issuer URI using BouncyCastle
Optional caIssuerURI = extractAIAUriUsingBC(aiaExtension);
chain = downloadCertificateChain(caIssuerURI.get(), certificate);
return chain;
}

// Method to extract the AIA URI using BouncyCastle
private static Optional extractAIAUriUsingBC(byte[] aiaExtension) {
try (ASN1InputStream asn1InputStream = new ASN1InputStream(aiaExtension)) {
ASN1Primitive derObject = asn1InputStream.readObject();
if (derObject instanceof DEROctetString) {
derObject = ASN1Primitive.fromByteArray(((DEROctetString) derObject).getOctets());
}
AuthorityInformationAccess aia = AuthorityInformationAccess.getInstance(derObject);
if (aia != null) {
for (AccessDescription accessDescription : aia.getAccessDescriptions()) {
if (X509ObjectIdentifiers.id_ad_caIssuers.equals(accessDescription.getAccessMethod())) {
GeneralName generalName = accessDescription.getAccessLocation();
if (generalName.getTagNo() == GeneralName.uniformResourceIdentifier) {
String uri = generalName.getName().toString();
return Optional.of(uri);
}
}
}
}
} catch (Exception e) {
System.err.println("Error processing AIA extension: " + e.getMessage());
}
return Optional.empty();
}

// Method to download the CA certificate chain
private static List downloadCertificateChain(String uri, X509Certificate certificat) throws Exception {
System.out.println("Downloading certificate from: " + uri);
Security.addProvider(new BouncyCastleProvider());
URL url = new URL(uri);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
try (InputStream inputStream = connection.getInputStream()) {
byte[] pkcs7Bytes = readAllBytesFromInputStream(inputStream);
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
Collection

Подробнее здесь: [url]https://stackoverflow.com/questions/79267552/sign-pdf-using-itext-java-with-certificate-in-cloud-with-no-container-cms-naked[/url]
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»