Статус: Новичок
Группы: Участники
Зарегистрирован: 16.11.2022(UTC) Сообщений: 4 Откуда: СПб
|
В итоге все получилось. Да, под ECGOST3410-2012 товарищи понимают упакованную в CMS подпись (PKCS#7 detached), поэтому базисом для решения задачки является файл samples-sources/CMS_samples/CMS.java из дистрибутива. Прикладываю ниже код, который у меня заработал. Важное — у ИПС как-то кривенько настроены серверы, поэтому полноценный CMS туда не пролезает по размеру заголовка. По совету их СТП из CMS были убраны данные сертификата (он все равно передается еще и в заголовке JWT), см. закомментированные строки в createCMS. Код:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.objsys.asn1j.runtime.*;
import kong.unirest.*;
import org.apache.commons.codec.binary.Base64;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.*;
import ru.CryptoPro.JCP.ASN.PKIX1Explicit88.CertificateSerialNumber;
import ru.CryptoPro.JCP.ASN.PKIX1Explicit88.Name;
import ru.CryptoPro.JCP.JCP;
import ru.CryptoPro.JCP.KeyStore.HDImage.HDImageStore;
import ru.CryptoPro.JCP.params.OID;
import ru.CryptoPro.JCP.tools.AlgorithmUtility;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
public class Application {
public static byte[] signCMS(
byte[] data, PrivateKey key, Certificate cert, boolean detached) throws Exception {
String keyAlg = key.getAlgorithm();
String signOid = AlgorithmUtility.keyAlgToSignatureOid(keyAlg);
// sign
final Signature signature = Signature.getInstance(signOid, JCP.PROVIDER_NAME);
signature.initSign(key);
signature.update(data);
final byte[] sign = signature.sign();
// create cms format
return createCMS(data, sign, cert, detached);
}
public static byte[] createCMS(
byte[] buffer, byte[] sign, Certificate cert, boolean detached) throws Exception {
String pubKeyAlg = cert.getPublicKey().getAlgorithm();
String digestOid = AlgorithmUtility.keyAlgToDigestOid(pubKeyAlg);
String keyOid = AlgorithmUtility.keyAlgToKeyAlgorithmOid(pubKeyAlg); // алгоритм ключа подписи
final String STR_CMS_OID_SIGNED = "1.2.840.113549.1.7.2";
final ContentInfo all = new ContentInfo();
all.contentType = new Asn1ObjectIdentifier(
new OID(STR_CMS_OID_SIGNED).value);
final SignedData cms = new SignedData();
all.content = cms;
cms.version = new CMSVersion(1);
// digest
cms.digestAlgorithms = new DigestAlgorithmIdentifiers(1);
final DigestAlgorithmIdentifier a = new DigestAlgorithmIdentifier(
new OID(digestOid).value);
a.parameters = new Asn1Null();
cms.digestAlgorithms.elements[0] = a;
final String STR_CMS_OID_DATA = "1.2.840.113549.1.7.1";
if (detached) {
cms.encapContentInfo = new EncapsulatedContentInfo(
new Asn1ObjectIdentifier(
new OID(STR_CMS_OID_DATA).value), null);
} // if
else {
cms.encapContentInfo =
new EncapsulatedContentInfo(new Asn1ObjectIdentifier(
new OID(STR_CMS_OID_DATA).value),
new Asn1OctetString(buffer));
} // else
// certificate
// cms.certificates = new CertificateSet(1);
// final ru.CryptoPro.JCP.ASN.PKIX1Explicit88.Certificate certificate =
// new ru.CryptoPro.JCP.ASN.PKIX1Explicit88.Certificate();
// final Asn1BerDecodeBuffer decodeBuffer =
// new Asn1BerDecodeBuffer(cert.getEncoded());
// certificate.decode(decodeBuffer);
//
// cms.certificates.elements = new CertificateChoices[1];
// cms.certificates.elements[0] = new CertificateChoices();
// cms.certificates.elements[0].set_certificate(certificate);
// signer info
cms.signerInfos = new SignerInfos(1);
cms.signerInfos.elements[0] = new SignerInfo();
cms.signerInfos.elements[0].version = new CMSVersion(1);
cms.signerInfos.elements[0].sid = new SignerIdentifier();
final byte[] encodedName = ((X509Certificate) cert)
.getIssuerX500Principal().getEncoded();
final Asn1BerDecodeBuffer nameBuf = new Asn1BerDecodeBuffer(encodedName);
final Name name = new Name();
name.decode(nameBuf);
final CertificateSerialNumber num = new CertificateSerialNumber(
((X509Certificate) cert).getSerialNumber());
cms.signerInfos.elements[0].sid.set_issuerAndSerialNumber(
new IssuerAndSerialNumber(name, num));
cms.signerInfos.elements[0].digestAlgorithm =
new DigestAlgorithmIdentifier(new OID(digestOid).value);
cms.signerInfos.elements[0].digestAlgorithm.parameters = new Asn1Null();
cms.signerInfos.elements[0].signatureAlgorithm =
new SignatureAlgorithmIdentifier(new OID(keyOid).value);
cms.signerInfos.elements[0].signatureAlgorithm.parameters = new Asn1Null();
cms.signerInfos.elements[0].signature = new SignatureValue(sign);
// encode
final Asn1BerEncodeBuffer asnBuf = new Asn1BerEncodeBuffer();
all.encode(asnBuf, true);
return asnBuf.getMsgCopy();
}
public static void main(String[] args) throws Exception {
final String storePath = "...";
final String storePass = "...";
final String systemId = "...";
Security.addProvider(new ru.CryptoPro.JCP.JCP());
HDImageStore.setDir(storePath);
KeyStore keystore = KeyStore.getInstance(JCP.HD_STORE_NAME);
keystore.load(null, null);
X509Certificate certificate =
(X509Certificate) keystore.getCertificate(keystore.aliases().nextElement());
PrivateKey privateKey = (PrivateKey) keystore.getKey(
keystore.aliases().nextElement(), storePass.toCharArray());
ObjectMapper mapper = new ObjectMapper();
var header = mapper.createObjectNode();
header.putArray("x5c").add(certificate.getEncoded());
header.put("alg", "ECGOST3410-2012");
var payload = mapper.createObjectNode();
payload.put("sub", systemId);
payload.put("aud", "https://ips-test.rosminzdrav.ru");
payload.put("iat", Instant.now().getEpochSecond());
payload.put("exp", Instant.now().plus(1, ChronoUnit.MINUTES).getEpochSecond());
String jwt = "%s.%s".formatted(
Base64.encodeBase64URLSafeString(header.toString().getBytes(StandardCharsets.UTF_8)),
Base64.encodeBase64URLSafeString(payload.toString().getBytes(StandardCharsets.UTF_8)));
byte[] data = jwt.getBytes(StandardCharsets.UTF_8);
byte sign[] = signCMS(data, privateKey, certificate, true, JCP.PROVIDER_NAME);
String authorization = "Bearer %s.%s".formatted(jwt, Base64.encodeBase64URLSafeString(sign));
final HttpResponse<String> response = Unirest
.get("https://ips-test.rosminzdrav.ru/4f52d90e921a0/v2/org?orgTypeId=1&offset=0&limit=5")
.header("Host", "ips-test.rosminzdrav.ru")
.header("Authorization", authorization)
.asString();
System.out.println(response.getBody());
}
}
|