📜 ⬆️ ⬇️

Escape from Crypto Pro. Director's version, SMEV-edition

This article focuses on how to stop using Crypto Pro and switch to Bouncy Castle in a development / test environment.
At the beginning of the article there will be more about SMEV and its client, at the end - more about converting keys from the finished copy-paste so that you can start right now.


Picture to attract attention:


image

And immediately the answer:


image

Disclamer


Of course, it is impossible to escape with Krypto Pro, because it is a stronghold of Russian cryptography. He satisfies the requirements of the competent authorities, he is registered in contracts and contracts, the whole country trusts him, and so on. Therefore, all of the following applies to the developer or test environment, where we are our own masters.


Recently, I needed to figure out how to write a service that works with the System of Interagency Electronic Interaction.
All written is simply the result of a small study, the most abstracted from the work performed. And even approximately to guess something about the decisions actually made is impossible, I checked.


Justification of the need for a finished client


The source code of the client lies on the SMEV3 technology portal, but what a bad luck - they are nailed to CryptoPro. The Word file with the instruction attached to the source code states this in the most direct way. And anyway, the source keys are also in CryptoPro format. Based on production, this is normal, but for the test environment it is terribly inconvenient. I would like to get rid of it.


The site has two versions - "current" and "recommended." Why they are so, and why the current version is not recommended, and the recommended one is not relevant - some kind of dilemma of a copywriter :) Then we’re talking about a client who is “relevant”.


Strictly speaking, it cannot be used, because there is no license text in the source archive, and therefore it is not clear under which license the derivative work should be distributed. I called the support phone number written on the portal, wrote an e-mail, watched a couple of weeks as my application flies between technical support levels and executing organizations, and as a result, it’s still there:


image


The task is not completed, but completed and closed, amazingly. Well, to hell with them ...


Despite the inability to use it directly in the code, this is a great test example. The fact is that the methodological recommendations of SMEV without pollitres cannot be understood, and the ready-made live code gives an excellent boost to understanding.


The main complaint about the documentation is clericals and a poor description on the Internet.
Remember the meme about the copywriter, who from the paragraph made one sentence in a few words? For SMEV documentation, this is the place to be, for example, here is a chain of refactorins for one phrase taken for granted:


"2. The consumer's IP sends an interdepartmental request to SMEV;"
"2. The consumer’s IP sends a request to SMEV;"
"2. The consumer’s IP sends the request;"
"2. the consumer sends a request;"
"2. consumer request;"


In short, having a ready-made implementation is good.


Why Krypto Pro JCP is Good



Why Krypto Pro JCP is Evil



As an alternative, in a test environment, I would prefer to use Bouncy Castle with a PKCS12 or JKS container. It is open, free and free software.
To the credit of the developers of Krypto Pro, they seem to have taken part in its development.


What you need to finish in the finished client to escape with Krypto Pro


The code is written quite friendly for the extension, so you can simply take the KeyStoreWrapperJCP class as the basis, and write KeyStoreWrapperBouncyCastlePKCS12, KeyStoreWrapperBouncyCastleJKS in the same way.


Rewrite DigitalSignatureFactory so that it starts to accept the path to the cryptocontainer on the file system and the password from it (for CryptoPro, this is simply not necessary). There is a switch that checks the type of the crypto-provider, add two additional cases to it, for names like BOUNCY_JKS and BOUNCY_PKCS12 and hang up using the appropriate KeyWrapper and call initXmlSec.


In initXmlSec you need to add
1) the ability to accept any provider at all, not just cryptopro (it is just convenient)
2) Security.addProvider (new BouncyCastleProvider ());
3) for XMLDSIG_SIGN_METHOD, make a switch: if CryptoPro, the algorithm is called "GOST3411withGOST3410EL", and if the BouncyCastle algorithm is called "GOST3411WITHECGOST3410".


Well, sort of like everything. If the license for this smav client was known, I would attach specific code under the Apache License 2, and this is just a list of ideas.


Initializing XML Signatures in Santuario


Oh yeah, there is one interesting point. There are a lot of advice on SMEV in the network, consisting in manual parsing of XMLk pieces and manually setting the sun at sunset, but this is not our method (and not the method used by the client’s creators)


The batch is that it is easy to generate self-signed keys according to GOST (a copy-paste to SO is searched for in seconds). But to sign - no, because in the opinion of online schoolchildren, allegedly Bouncycastle does not support xml-signature. More specifically, when working with Apache Santuario, XMLSignature from santuario-xmlsec does not understand what to use to handle the "xmldsig-more # gostr34102001-gostr3411" method when calling xmlSignature.sign (privateKey).


Separate Hochma is that the IntelliJ IDEA Community is buggy when you try to detach xmlsec by throwing the step in debugger in the wrong place with the correct source code. I tried all the sensible versions of Idea, so understand how it works blindly, writing tactical letters in Sportloto. This is not a reproach to the Idea, there are no perfect tools, just a factor that influenced the speed of understanding the issue.


To make it work, you need:


1) Implement the SignatureAlgorithmSpi implementation from Apache Santuario. In GetEngineUri, return the string: " http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411 " (or whatever you have). This is the key magic. Absolutely nothing clever this class should not do.


Initialization of the application's lifetime (for example, in the singleton bean of the spring):


2) Download the provider so as not to patch the JDK:


Security.addProvider(new BouncyCastleProvider()); 

3) Go to runtime just-written class:


 String algorithmClassName = "fully qualified name   SignatureAlgorithmSpi"; Class.forName(algorithmClassName); SignatureAlgorithm.providerInit(); SignatureAlgorithm.register("http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411", algorithmClassName); 

4) Knocking on JCE mapping algorithms:


 String ns = "http://www.xmlsecurity.org/NS/#configuration"; Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); Element rootElement = document.createElementNS(ns, "JCEAlgorithmMappings"); Element algorithms = document.createElementNS(ns, "Algorithms"); 

5) Zapit method for the algorithm:


 Element aElem = document.createElementNS(NameSpace, "Algorithm"); aElem.setAttribute("URI", "http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411"); aElem.setAttribute("Description", "GOST R 34102001 Digital Signature Algorithm with GOST R 3411 Digest"); aElem.setAttribute("AlgorithmClass", "Signature"); aElem.setAttribute("RequirementLevel", "OPTIONAL"); aElem.setAttribute("JCEName", "GOST3411WITHECGOST3410"); algorithms.appendChild(aElem); 

6) Apply mappings:


 org.apache.xml.security.Init.init(); JCEMapper.init(rootElement); 

6) PROFIT!
After this, XMLSignature abruptly begins to understand this method, and will begin to make xmlSignature.sign.


OpenSSL preparation for working with GOST


If you have OpenSSL on the wall at the beginning of the article, someday it will definitely shoot.
So yes, this is an important point, necessary for the implementation of further text.



How can we ask Krypto Pro to hand over the keys (actually, no)


If we already have real (not self-signed) keys, then it would be completely unreasonable to check them in action. Yes, we are talking about test purposes, but still trust - but check!


If you put the Windows in a virtual machine, roll Krypto Pro there, install the keys and try to export them, then we find an amazing thing: the export to PKCS12 does not work in the exporter, and all other directions in the exporter are blocked (English "grayed out").


I google a mistake, and what do we see on the official forum?
https://www.cryptopro.ru/forum2/default.aspx?g=posts&t=2425


"From Alexey Pisinin the answer was received:
Good day. PKCS12 does not meet the security requirements of the FSB regarding the storage of private keys. In theory, private keys should be stored on so-called "removable" media. Actually, for this reason, the export does not work. "


I read it correctly, what do they have for export, but I don’t have business logic to it?
For any ticks, do not click - there will always be an error on the last step of the wizard !?


What a shame.


Dear god
Please kill them all.
Love, Greg.


image


How can we roughly force Krypto Pro to give away the keys


You can suffer for a very long time trying to roll up C ++ to subtract the key from the container using OpenSSL and such and such mother. I honestly tried, and crashed about the task like a ship on the rocks (at least, this is a task for more than 1 day for a person who hasn’t been doing this for a long time). On the Internet, we are not the only ones who crashed on the same rocks: http://gigamir.net/techno/pub903517


Here comes the moment "this is joy with tears in his eyes." A certain office called Lissy Soft, for only 2 thousand rubles, gives us the ingenious utility P12FromGostCSP. Its creators did defeat the problem that the community had not mastered, and it tears out the keys in PFX. Joy - because it works.


With tears - because it is proprietary, and she knows how she works.
In the picture, Richard Stallman seems to be surprised and asks: "Are you really fighting proprietary with the help of another proprietary one?"


image


So the whole instruction on driving the keys looks something like this:



Test self-signed keys


Since we are doing all this for test purposes, now we come to a climax and begin to give ourselves the keys.


How to issue keys in the Crypto Pro format, I did not particularly bother, because it simply is not necessary in the framework of the current task. But just in case, there is a service for issuing such keys: http://www.cryptopro.ru/certsrv/



JKS container delivery


This question is widely represented on the Internet, so you can immediately watch Stackoverflow:
http://stackoverflow.com/questions/14580340/generate-gost-34-10-2001-keypair-and-save-it-to-some-keystore


The idea is that since we still use Bouncy Castle, we can also generate the key.
This code is not the most ideal, but it gives a really working implementation (in practice, I ended up with several large classes to make a convenient interface)


 Security.addProvider( new org.bouncycastle.jce.provider.BouncyCastleProvider() ); KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( "ECGOST3410", "BC" ); keyPairGenerator.initialize( new ECGenParameterSpec( "GostR3410-2001-CryptoPro-A" ) ); KeyPair keyPair = keyPairGenerator.generateKeyPair(); org.bouncycastle.asn1.x500.X500Name subject = new org.bouncycastle.asn1.x500.X500Name( "CN=Me" ); org.bouncycastle.asn1.x500.X500Name issuer = subject; // self-signed BigInteger serial = BigInteger.ONE; // serial number for self-signed does not matter a lot Date notBefore = new Date(); Date notAfter = new Date( notBefore.getTime() + TimeUnit.DAYS.toMillis( 365 ) ); org.bouncycastle.cert.X509v3CertificateBuilder certificateBuilder = new org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder( issuer, serial, notBefore, notAfter, subject, keyPair.getPublic() ); org.bouncycastle.cert.X509CertificateHolder certificateHolder = certificateBuilder.build( new org.bouncycastle.operator.jcajce.JcaContentSignerBuilder( "GOST3411withECGOST3410" ) .build( keyPair.getPrivate() ) ); org.bouncycastle.cert.jcajce.JcaX509CertificateConverter certificateConverter = new org.bouncycastle.cert.jcajce.JcaX509CertificateConverter(); X509Certificate certificate = certificateConverter.getCertificate( certificateHolder ); KeyStore keyStore = KeyStore.getInstance( "JKS" ); keyStore.load( null, null ); // initialize new keystore keyStore.setEntry( "alias", new KeyStore.PrivateKeyEntry( keyPair.getPrivate(), new Certificate[] { certificate } ), new KeyStore.PasswordProtection( "entryPassword".toCharArray() ) ); keyStore.store( new FileOutputStream( "test.jks" ), "keystorePassword".toCharArray() 

Delivery of the PKCS12 container


In principle, this is not really necessary, because we already have a simple and convenient way to issue JKS, and JKS for Java is the most native solution. But to complete the picture, let it be.



Summary


As a result of all the above actions, we got a relatively easy way to get rid of the heavy burden of Krypto Pro.


In the future, I would like to continue the fight for the drunk before the final victory: arrange all utilities, key generators, self-written smav clients and so on in the form of one repository on GitHub. Also, I would very much like to receive the rights to modify and distribute under the permissive license of the official client of the SIEV. Then half of this article would simply not be needed, and the problem would be solved by downloading the necessary code from GitHub.


')

Source: https://habr.com/ru/post/282225/


All Articles