package com.isbc.smartcard.esmarttoken.api;

import java.io.*;
import java.util.*;

import javax.smartcardio.*;

import org.apache.log4j.Logger;

import com.isbc.smartcard.esmarttoken.utils.*;
import com.isbc.smartcard.esmarttoken.utils.TerminalUtilsImpl.CARDTYPE;

/**
 * Find and personalized first available and valid EsmartToken card
 * @author Sergey Panov 
 */
public class Console
{
	private static Logger logger = Logger.getLogger(Console.class);
	private static final long SIGN_EXPIRED_CERT_ERROR = 2147485184L;
	
	private Console() {}
	
	public static void main(String[] args) throws Exception
	{
		 Scanner reader = new Scanner(System.in);
	     System.out.println("This programm will perform some tests.\n"
	      		+ "These tests erase all data on token/smart-card.\n"
	      		+ "Continue? [yes/no]: ");
	     String line = reader.nextLine();
	     
	     if (!line.equalsIgnoreCase("yes"))
	     {
	    	 System.out.println("Abort.");
	    	 return;
	     }
		
		int count = 1;
		int attempt = 0;
		if (args != null && args.length > 0)
		{
			count = Integer.valueOf(args[0]);
		}
		boolean isSkipInitToken = false;
		if (args.length > 0)
		{
			for (String s: args)
			{
				if (s.compareToIgnoreCase("--skip-init-token") == 0)
				{
					isSkipInitToken = true;
				}
			}
		}
		logger.info("Start testing " + count + " time(s).");
		
		Pkcs11Wrapper wrapper = new Pkcs11Wrapper();
		
		String os_name = System.getProperty("os.name").toLowerCase();
		String module = null;
	    logger.info("OS name: " + os_name);
	    if (os_name.indexOf("windows") > -1)
	    {
	    	module = "isbc_pkcs11_main.dll";
	    }
	    else if (os_name.indexOf("mac os") > -1)
	    {
	    	module = "libisbc_pkcs11_main.dylib";
	    }
	    else
	    {
	    	module = "libisbc_pkcs11_main.so";
	    }
	    
	    try
	    {
			TerminalUtils.loadConfig("../conf/pkcs11.conf");
		}
	    catch (IOException e) {
	    	logger.error("Failed to load config file", e);
		}
	    
	    CardTerminal terminal = null;
		try
		{
			terminal = TerminalUtils.getFirstValidTerminal();
		    logger.info("Token UID: " + TerminalUtils.getCardUID(terminal));
		}
		catch (Exception e)
		{
			logger.error("Get UID error", e);
		}
		
		long res = -1;
		long startTime = System.currentTimeMillis();
		long startAttemtpTime;
		
		while(count > attempt)
		{
			++attempt;
			startAttemtpTime = System.currentTimeMillis();
			logger.info("Start attempt " + attempt + " of " + count);
			
			if (!isSkipInitToken)
			{
				logger.info("Trying to perform init token usign default pin");
				res = wrapper.initCardWrap(null, module, "12345678".getBytes());
				logger.info("initCardWrap result: " + res);
				if (res != 0)
				{
					logger.error("Stop checking because of error " + res + 
							" on attempt " + attempt + " of " + count);
					break;
				}
			}
			else
			{
				logger.info("Skip init token");
			}

			logger.info("Trying to load test certificate and private key from PKCS#12 file");
			FileInputStream file;
			byte[] buffer = null;
			try
			{
				file = new FileInputStream("../conf/clientTest2.p12");
		        int numberBytes = file.available();
		        buffer = new byte[numberBytes];
		        file.read(buffer);
		        file.close();
		        
		        res = wrapper.loadCertWrap(null, module, buffer, "123".getBytes(), "12345678".getBytes());
				logger.info("loadCertWrap result: " + res);
				if (res != 0)
				{
					logger.error("Stop checking because of error " + res + 
							" on attempt " + attempt + " of " + count);
					break;
				}
			}
			catch (Exception e)
			{
				logger.error("Read file error", e);
				if (res != 0)
				{
					logger.error("Stop checking because of error " + e.getMessage() + 
							" on attempt " + attempt + " of " + count);
					break;
				}
			}
			
			Card card = terminal.connect("*");
			String atr = HexUtils.encodeHexString(card.getATR().getBytes());
			card.disconnect(true);
			
			if (TerminalUtils.getCardTypeByATR(atr) == CARDTYPE.ESMART_TOKEN_GOST)
			{
				logger.info("Trying to load test GOST certificate and private key from PKCS#12 file");
				try
				{
					file = new FileInputStream("../conf/clientGostA.p12");
			        int numberBytes = file.available();
			        buffer = new byte[numberBytes];
			        file.read(buffer);
			        file.close();
			        
			        res = wrapper.loadCertWrap(null, module, buffer, "123".getBytes(), "12345678".getBytes());
					logger.info("loadCertWrap result: " + res);
					if (res != 0)
					{
						logger.error("Stop checking GOST cert because of error " + res + 
								" on attempt " + attempt + " of " + count);
						break;
					}
				}
				catch (Exception e)
				{
					logger.error("Read file error", e);
					if (res != 0)
					{
						logger.error("Stop checking because of error " + e.getMessage() + 
								" on attempt " + attempt + " of " + count);
						break;
					}
				}
			}
				
			logger.info("Trying to load test X509 certificate in DER format");
			try
			{
				file = new FileInputStream("../conf/ca.crt");
		        int numberBytes = file.available();
		        buffer = new byte[numberBytes];
		        file.read(buffer);
		        file.close();
		        
		        res = wrapper.loadX509CertificateWrap(null, module, "12345678".getBytes(), "newCAcert", HexUtils.decodeHex("1122334455"), buffer);
				logger.info("loadX509CertificateWrap result: " + res);
				if (res != 0)
				{
					logger.error("Stop checking because of error " + res + 
							" on attempt " + attempt + " of " + count);
					break;
				}
			}
			catch (Exception e)
			{
				logger.error("Read file error", e);
				if (res != 0)
				{
					logger.error("Stop checking because of error " + e.getMessage() + 
							" on attempt " + attempt + " of " + count);
					break;
				}
			}
			
			if (TerminalUtils.getCardTypeByATR(atr) == CARDTYPE.ESMART_TOKEN_GOST ||
				TerminalUtils.getCardTypeByATR(atr) == CARDTYPE.ESMART_TOKEN_MSKEY)
			{
				logger.info("Trying to load test X509 GOST certificate in DER format");
				try
				{
					file = new FileInputStream("../conf/ca_gost.crt");
			        int numberBytes = file.available();
			        buffer = new byte[numberBytes];
			        file.read(buffer);
			        file.close();
			        
			        res = wrapper.loadX509CertificateWrap(null, module, "12345678".getBytes(), "newCA_GOSTcert", HexUtils.decodeHex("6677889900"), buffer);
					logger.info("loadX509CertificateWrap result: " + res);
					if (res != 0)
					{
						logger.error("Stop checking because of error " + res + 
								" on attempt " + attempt + " of " + count);
						break;
					}
				}
				catch (Exception e)
				{
					logger.error("Read file error", e);
					if (res != 0)
					{
						logger.error("Stop checking because of error " + e.getMessage() + 
								" on attempt " + attempt + " of " + count);
						break;
					}
				}
			}
			
			logger.info("Try to generate RSA 1024 key pair");
			res = wrapper.generateKeyPairWrap(null, module, "12345678".getBytes(), 1024, "new1024key", HexUtils.decodeHex("1024"));
			logger.info("generateKeyPairWrap result: " + res);
			if (res != 0)
			{
				logger.error("Stop checking because of error " + res + 
						" on attempt " + attempt + " of " + count);
				break;
			}
			
			if (TerminalUtils.getCardTypeByATR(atr) != CARDTYPE.ESMART_TOKEN_GOST &&
				TerminalUtils.getCardTypeByATR(atr) != CARDTYPE.ESMART_TOKEN_MSKEY)
			{
				logger.info("Try to generate RSA 2048 key pair");
				res = wrapper.generateKeyPairWrap(null, module, "12345678".getBytes(), 2048, "new2048key", HexUtils.decodeHex("2048"));
				logger.info("generateKeyPairWrap result: " + res);
				if (res != 0)
				{
					logger.error("Stop checking because of error " + res + 
							" on attempt " + attempt + " of " + count);
					break;
				}
			}
			else
			{
				logger.info("Try to generate GOST key pair");
				res = wrapper.generateGostR3410_2001KeyPairWrap(null, module, "12345678".getBytes(), "newGOSTkey", HexUtils.decodeHex("0256"));
				logger.info("generateGostR3410_2001KeyPairWrap result: " + res);
				if (res != 0)
				{
					logger.error("Stop checking because of error " + res + 
							" on attempt " + attempt + " of " + count);
					break;
				}
			}
			
			List<Pkcs11ObjectAttribute> attrList = new ArrayList<Pkcs11ObjectAttribute>();
			logger.info("Token objects enumeration");
			res = wrapper.listObjectsWrap(null, module, "12345678".getBytes(), attrList);
			Pkcs11ObjectAttribute certificate = null, publickeyRsa = null, signCertRsa = null, signPrivateKeyRsa = null;
			Pkcs11ObjectAttribute publickeyGost = null, signCertGost = null, signPrivateKeyGost = null;
			String containerIdRsa = null, containerIdGost = null;
			
		    for (int i = 0; i < attrList.size(); ++i)
		    {
		    	Pkcs11ObjectAttribute obj = attrList.get(i);
		    	logger.info("Type: " + obj.getType());
		    	logger.info("Label: " + obj.getLabel());
		    	logger.info("ID: " + obj.getId());
		    	logger.info("KeyType: " + obj.getKeyType());
		    	
		    	if (obj.getType().equals("certificate"))
		    	{
		    		// Store last cert obj to download later
		    		certificate = obj;
		    		
		    		if (obj.getLabel().indexOf("Import") >= 0 && obj.getId().equals(containerIdRsa))
		    		{
		    			signCertRsa = obj;
		    		}
		    		else if (obj.getLabel().indexOf("Import") >= 0 && obj.getId().equals(containerIdGost))
		    		{
		    			signCertGost = obj;
		    		}
		    	}
		    	else if (obj.getType().equals("public key"))
		    	{
		    		// Store last public key obj to download later
		    		if (obj.getKeyType() != null && obj.getKeyType().equals("RSA"))
		    		{
		    			publickeyRsa = obj;
		    		}
		    		else if (obj.getKeyType() != null && obj.getKeyType().equals("GOSTR3410"))
		    		{
		    			publickeyGost = obj;
		    		}
		    	}
		    	else if (obj.getType().equals("private key"))
		    	{
		    		if (obj.getLabel().indexOf("Import") >= 0)
		    		{
			    		if (obj.getKeyType() != null && obj.getKeyType().equals("RSA"))
			    		{
			    			signPrivateKeyRsa = obj;
			    			containerIdRsa = obj.getId();
			    		}
			    		else if (obj.getKeyType() != null && obj.getKeyType().equals("GOSTR3410"))
			    		{
			    			signPrivateKeyGost = obj;
			    			containerIdGost = obj.getId();
			    		}
		    		}
		    	}
		    }
		    
		    logger.info("listObjects result: " + res);
		    if (res != 0)
			{
				logger.error("Stop checking because of error " + res + 
						" on attempt " + attempt + " of " + count);
				break;
			}
		    
		    if (certificate != null)
		    {
		    	logger.info("Trying to get certificate: " + certificate.getLabel() + 
		    			" with id " + certificate.getId());
			    List<Byte> buffer2 = new ArrayList<Byte>();
			    res = wrapper.getX509CertificateWrap(null, module, "12345678".getBytes(), certificate.getLabel(), 
			    		HexUtils.decodeHex(certificate.getId()), buffer2);
				logger.info("getX509CertificateWrap result: " + res + " buffer size: " + buffer2.size());
				if (res != 0)
				{
					logger.error("Stop checking because of error " + res + 
							" on attempt " + attempt + " of " + count);
					break;
				}
				
				if (!buffer2.isEmpty())
				{
					FileOutputStream file2;
					try
					{
						file2 = new FileOutputStream("testcert.cer");
						for (int i=0; i < buffer2.size(); ++i)
						{
							file2.write(buffer2.get(i).byteValue());
						}
						file2.close();
						logger.info("Certificate saved to testcert.cer");
					}
					catch (Exception e)
					{
						logger.error("Write file error", e);
						if (res != 0)
						{
							logger.error("Stop checking because of error " + e.getMessage() + 
									" on attempt " + attempt + " of " + count);
							break;
						}
					}
				}
		    }
		    
		    if (publickeyRsa != null)
		    {
		    	logger.info("Trying to get public key: " + publickeyRsa.getLabel() + 
		    			" with id " + publickeyRsa.getId());
			    List<Byte> modulusData = new ArrayList<Byte>();
			    List<Byte> exponentData = new ArrayList<Byte>();
			    res = wrapper.getPublicKeyWrap(null, module, "12345678".getBytes(), publickeyRsa.getLabel(),
			    		HexUtils.decodeHex(publickeyRsa.getId()), modulusData, exponentData);
				logger.info("getPublicKeyWrap result: " + res + 
						" modulusData size: " + modulusData.size() + " exponentData size: " + exponentData.size());
				if (res != 0)
				{
					logger.error("Stop checking because of error " + res + 
							" on attempt " + attempt + " of " + count);
					break;
				}
				
				if (!modulusData.isEmpty())
				{
					FileOutputStream file2;
					try
					{
						file2 = new FileOutputStream("modulus.data");
						for (int i=0; i < modulusData.size(); ++i)
						{
							file2.write(modulusData.get(i).byteValue());
						}
						file2.close();
						logger.info("modulusData saved to modulus.data");
					}
					catch (Exception e)
					{
						logger.error("Write file error", e);
						if (res != 0)
						{
							logger.error("Stop checking because of error " + e.getMessage() + 
									" on attempt " + attempt + " of " + count);
							break;
						}
					}
					try
					{
						file2 = new FileOutputStream("exponent.data");
						for (int i=0; i < exponentData.size(); ++i)
						{
							file2.write(exponentData.get(i).byteValue());
						}
						file2.close();
						logger.info("exponentData saved to exponent.data");
					}
					catch (Exception e)
					{
						logger.error("Write file error", e);
						if (res != 0)
						{
							logger.error("Stop checking because of error " + e.getMessage() + 
									" on attempt " + attempt + " of " + count);
							break;
						}
					}
				}
				
				logger.info("Trying to create CSR for: " + publickeyRsa.getLabel() + 
		    			" with id " + publickeyRsa.getId());
				List<Byte> buffer3 = new ArrayList<Byte>();
				List<String> dn = new ArrayList<String>();
				dn.add("CN");
				dn.add("Ivan Ivanov");
				dn.add("emailAddress");
				dn.add("ivanov@mail.ru");
				
				List<String> attr = new ArrayList<String>();
				attr.add("challengePassword");
		        attr.add("123");
				
				List<String> ext = new ArrayList<String>();
		        ext.add("keyUsage");
		        ext.add("digitalSignature,keyEncipherment");
		        ext.add("1");
		        
		        ext.add("subjectAltName");
		        ext.add("DNS:isbc.ru");
		        ext.add("1");
	
		        ext.add("extendedKeyUsage");
		        ext.add("1.3.6.1.4.1.311.20.2.2");
		        ext.add("0");
				
				res = wrapper.createCSRWrap(null, module, "12345678".getBytes(), 
					HexUtils.decodeHex(publickeyRsa.getId()),
					HexUtils.decodeHex(publickeyRsa.getId()), 
					dn.toArray(new String[]{}), attr.toArray(new String[]{}), ext.toArray(new String[]{}), buffer3);
				
				logger.info("createCSRWrap result: " + res + " buffer size: " + buffer3.size());
				if (res != 0)
				{
					logger.error("Stop checking because of error " + res + 
							" on attempt " + attempt + " of " + count);
					break;
				}
				
				if (!buffer3.isEmpty())
				{
					FileOutputStream file2;
					try
					{
						file2 = new FileOutputStream("testcsr.csr");
						for (int i=0; i < buffer3.size(); ++i)
						{
							file2.write(buffer3.get(i).byteValue());
						}
						file2.close();
						logger.info("CSR saved to test.csr");
					}
					catch (Exception e)
					{
						logger.error("Write file error", e);
						if (res != 0)
						{
							logger.error("Stop checking because of error " + e.getMessage() + 
									" on attempt " + attempt + " of " + count);
							break;
						}
					}
				}
		    }
		    
		    if (publickeyGost != null && 
		    		(TerminalUtils.getCardTypeByATR(atr) == CARDTYPE.ESMART_TOKEN_GOST ||
		    		TerminalUtils.getCardTypeByATR(atr) == CARDTYPE.ESMART_TOKEN_MSKEY))
		    {
				logger.info("Trying to create GOST CSR for: " + publickeyRsa.getLabel() + 
		    			" with id " + publickeyRsa.getId());
				List<Byte> buffer3 = new ArrayList<Byte>();
				List<String> dn = new ArrayList<String>();
				dn.add("CN");
				dn.add("Ivan Ivanov GOST");
				dn.add("emailAddress");
				dn.add("ivanov@mail.ru");
				
				List<String> attr = new ArrayList<String>();
				attr.add("challengePassword");
		        attr.add("123");
				
				List<String> ext = new ArrayList<String>();
		        ext.add("keyUsage");
		        ext.add("digitalSignature,keyEncipherment");
		        ext.add("1");
		        
		        ext.add("subjectAltName");
		        ext.add("DNS:isbc.ru");
		        ext.add("1");
	
		        ext.add("extendedKeyUsage");
		        ext.add("1.3.6.1.4.1.311.20.2.2");
		        ext.add("0");
				
				res = wrapper.createCSRWrap(null, module, "12345678".getBytes(), 
					HexUtils.decodeHex(publickeyGost.getId()),
					HexUtils.decodeHex(publickeyGost.getId()), 
					dn.toArray(new String[]{}), attr.toArray(new String[]{}), ext.toArray(new String[]{}), buffer3);
				
				logger.info("createCSRWrap result: " + res + " buffer size: " + buffer3.size());
				if (res != 0)
				{
					logger.error("Stop checking because of error " + res + 
							" on attempt " + attempt + " of " + count);
					break;
				}
				
				if (!buffer3.isEmpty())
				{
					FileOutputStream file2;
					try
					{
						file2 = new FileOutputStream("testcsr_gost.csr");
						for (int i=0; i < buffer3.size(); ++i)
						{
							file2.write(buffer3.get(i).byteValue());
						}
						file2.close();
						logger.info("CSR saved to testcsr_gost.csr");
					}
					catch (Exception e)
					{
						logger.error("Write file error", e);
						if (res != 0)
						{
							logger.error("Stop checking because of error " + e.getMessage() + 
									" on attempt " + attempt + " of " + count);
							break;
						}
					}
				}
		    }
		    
		    if (signPrivateKeyRsa != null && signCertRsa != null)
		    {
			    logger.info("Trying to sign data in PKCS#7 format");
				List<Byte> buffer3 = new ArrayList<Byte>();
				res = wrapper.pkcs7SignWrap(null, module, "12345678".getBytes(), "SIGNDATA".getBytes(), 
						HexUtils.decodeHex(signPrivateKeyRsa.getId()), 
						HexUtils.decodeHex(signCertRsa.getId()), 
						null, 0x00, buffer3);

				if (res == SIGN_EXPIRED_CERT_ERROR)
				{
					logger.info("pkcs7SignWrap certificate has expired and can't be used for sign");
				}
				else
				{
					logger.info("pkcs7SignWrap result: " + res + " buffer size: " + buffer3.size());
				}
				
				if (res != 0)
				{
					logger.error("Stop checking because of error " + res + 
							" on attempt " + attempt + " of " + count);
					break;
				}
				
				if (!buffer3.isEmpty())
				{
					FileOutputStream file3;
					try
					{
						file3 = new FileOutputStream("signedData.p7");
						for (int i=0; i < buffer3.size(); ++i)
						{
							file3.write(buffer3.get(i).byteValue());
						}
						file3.close();
						logger.info("Signed data saved to signedData.p7");
					}
					catch (Exception e)
					{
						logger.error("Write file error", e);
						if (res != 0)
						{
							logger.error("Stop checking because of error " + e.getMessage() + 
									" on attempt " + attempt + " of " + count);
							break;
						}
					}
				}
				
				logger.info("Trying to verify data in PKCS#7 format");
				byte[] result = new byte[buffer3.size()];
				for(int i=0; i<buffer3.size(); i++){ 
				    result[i] = buffer3.get(i).byteValue();
				}
				res = wrapper.pkcs7VerifyWrap(module, result, null);
				logger.info("pkcs7VerifyWrap result: " + res);
				
				logger.info("Trying to sign data in PKCS#7 format detached");
				buffer3 = new ArrayList<Byte>();
				res = wrapper.pkcs7SignWrap(null, module, "12345678".getBytes(), "SIGNDATA".getBytes(), 
						HexUtils.decodeHex(signPrivateKeyRsa.getId()), 
						HexUtils.decodeHex(signCertRsa.getId()),
						null, 0x40, buffer3);

				if (res == SIGN_EXPIRED_CERT_ERROR)
				{
					logger.info("pkcs7SignWrap certificate has expired and can't be used for sign");
				}
				else
				{
					logger.info("pkcs7SignWrap result: " + res + " buffer size: " + buffer3.size());
				}
				
				if (res != 0)
				{
					logger.error("Stop checking because of error " + res + 
							" on attempt " + attempt + " of " + count);
					break;
				}
				
				if (!buffer3.isEmpty())
				{
					FileOutputStream file3;
					try
					{
						file3 = new FileOutputStream("signedData2.p7");
						for (int i=0; i < buffer3.size(); ++i)
						{
							file3.write(buffer3.get(i).byteValue());
						}
						file3.close();
						logger.info("Signed data saved to signedData2.p7");
					}
					catch (Exception e)
					{
						logger.error("Write file error", e);
						if (res != 0)
						{
							logger.error("Stop checking because of error " + e.getMessage() + 
									" on attempt " + attempt + " of " + count);
							break;
						}
					}
				}
				
				logger.info("Trying to verify data in PKCS#7 format detached");
				result = new byte[buffer3.size()];
				for(int i=0; i<buffer3.size(); i++){ 
				    result[i] = buffer3.get(i).byteValue();
				}
				res = wrapper.pkcs7VerifyWrap(module, result, "SIGNDATA".getBytes());
				logger.info("pkcs7VerifyWrap result: " + res);
		    	
		    }
		    
		    if (signPrivateKeyGost != null && signCertGost != null && 
		    		(TerminalUtils.getCardTypeByATR(atr) == CARDTYPE.ESMART_TOKEN_GOST ||
		    		TerminalUtils.getCardTypeByATR(atr) == CARDTYPE.ESMART_TOKEN_MSKEY))
		    {
			    logger.info("Trying to sign data in PKCS#7 format GOST cert");
				List<Byte> buffer3 = new ArrayList<Byte>();
				res = wrapper.pkcs7SignWrap(null, module, "12345678".getBytes(), "SIGNDATA-GOST".getBytes(), 
						HexUtils.decodeHex(signPrivateKeyGost.getId()), 
						HexUtils.decodeHex(signCertGost.getId()), 
						null, 0x00, buffer3);
				
				if (res == SIGN_EXPIRED_CERT_ERROR)
				{
					logger.info("pkcs7SignWrap certificate has expired and can't be used for sign");
				}
				else
				{
					logger.info("pkcs7SignWrap result: " + res + " buffer size: " + buffer3.size());
				}
				
				if (res != 0)
				{
					logger.error("Stop checking because of error " + res + 
							" on attempt " + attempt + " of " + count);
					break;
				}
				
				if (!buffer3.isEmpty())
				{
					FileOutputStream file3;
					try
					{
						file3 = new FileOutputStream("signedData_gost.p7");
						for (int i=0; i < buffer3.size(); ++i)
						{
							file3.write(buffer3.get(i).byteValue());
						}
						file3.close();
						logger.info("Signed data saved to signedData_gost.p7");
					}
					catch (Exception e)
					{
						logger.error("Write file error", e);
						if (res != 0)
						{
							logger.error("Stop checking because of error " + e.getMessage() + 
									" on attempt " + attempt + " of " + count);
							break;
						}
					}
				}
				
				logger.info("Trying to verify data in PKCS#7 format GOST");
				byte[] result = new byte[buffer3.size()];
				for(int i=0; i<buffer3.size(); i++){ 
				    result[i] = buffer3.get(i).byteValue();
				}
				res = wrapper.pkcs7VerifyWrap(module, result, null);
				logger.info("pkcs7VerifyWrap result: " + res);
				
				logger.info("Trying to sign data in PKCS#7 format detached GOST");
				buffer3 = new ArrayList<Byte>();
				res = wrapper.pkcs7SignWrap(null, module, "12345678".getBytes(), "SIGNDATA-GOST".getBytes(), 
						HexUtils.decodeHex(signPrivateKeyGost.getId()), 
						HexUtils.decodeHex(signCertGost.getId()),
						null, 0x40, buffer3);
				if (res == SIGN_EXPIRED_CERT_ERROR)
				{
					logger.error("pkcs7SignWrap certificate has expired and can't be used for sign");
				}
				else
				{
					logger.info("pkcs7SignWrap result: " + res + " buffer size: " + buffer3.size());
				}
				if (res != 0)
				{
					logger.error("Stop checking because of error " + res + 
							" on attempt " + attempt + " of " + count);
					break;
				}
				
				if (!buffer3.isEmpty())
				{
					FileOutputStream file3;
					try
					{
						file3 = new FileOutputStream("signedData2_gost.p7");
						for (int i=0; i < buffer3.size(); ++i)
						{
							file3.write(buffer3.get(i).byteValue());
						}
						file3.close();
						logger.info("Signed data saved to signedData2_gost.p7");
					}
					catch (Exception e)
					{
						logger.error("Write file error", e);
						if (res != 0)
						{
							logger.error("Stop checking because of error " + e.getMessage() + 
									" on attempt " + attempt + " of " + count);
							break;
						}
					}
				}
				
				logger.info("Trying to verify data in PKCS#7 format detached GOST");
				result = new byte[buffer3.size()];
				for(int i=0; i<buffer3.size(); i++){ 
				    result[i] = buffer3.get(i).byteValue();
				}
				res = wrapper.pkcs7VerifyWrap(module, result, "SIGNDATA-GOST".getBytes());
				logger.info("pkcs7VerifyWrap result: " + res);
		    	
		    }
			
		    logger.info("Try to change PIN");
			res = wrapper.setPinWrap(null, module, "12345678".getBytes(), "11111111".getBytes());
			logger.info("setPinWrap result: " + res);
			if (res != 0)
			{
				logger.error("Stop checking because of error " + res + 
						" on attempt " + attempt + " of " + count);
				break;
			}
			
			logger.info("Try to change PIN back to default");
			res = wrapper.setPinWrap(null, module, "11111111".getBytes(), "12345678".getBytes());
			logger.info("setPinWrap result: " + res);
			if (res != 0)
			{
				logger.error("Stop checking because of error " + res + 
						" on attempt " + attempt + " of " + count);
				break;
			}
			
			logger.info("Try to change PUK");
			res = wrapper.setPukWrap(null, module, "12345678".getBytes(), "11111111".getBytes());
			logger.info("setPukWrap result: " + res);
			if (res != 0)
			{
				logger.error("Stop checking because of error " + res + 
						" on attempt " + attempt + " of " + count);
				break;
			}
			
			logger.info("Try to change PUK back to default");
			res = wrapper.setPukWrap(null, module, "11111111".getBytes(), "12345678".getBytes());
			logger.info("setPukWrap result: " + res);
		    
		    logger.info("Cleaning card");
			res = wrapper.cleanCardWrap(null, module, "12345678".getBytes());
			logger.info("cleanCardWrap result: " + res);
			if (res != 0)
			{
				logger.error("Stop checking because of error " + res + 
						" on attempt " + attempt + " of " + count);
				break;
			}
			
			logger.info("End attempt " + attempt + " of " + count + 
					". Duration " + (int) (System.currentTimeMillis() - startAttemtpTime)/1000 +
					" seconds.");
			logger.info("======================================================================================");
			logger.info("======================================================================================");
		}
		
		logger.info("End cheking. " + attempt + " were perfomed for " 
				+ (int) (System.currentTimeMillis() - startTime)/1000 +
				" seconds.");
	}
}
