KaIIIuct,
По-моему менялись только два класса:
JcpFacade 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144. 145. 146. 147. 148. 149. 150. 151. 152. 153. 154. 155. 156. 157. 158. 159. 160. 161. 162. 163. 164. 165. 166. 167. 168. 169. 170. 171. 172. 173. 174. 175. 176. 177. 178. 179. 180. 181. 182. 183. 184. 185. 186. 187. 188. 189. 190. 191. 192. 193. 194. 195. 196. 197. 198. 199. 200. 201. 202. 203. 204. 205. 206. 207. 208. 209. 210. 211. 212. 213. 214. 215. 216. 217. 218. 219. 220. 221. 222. 223. 224. 225. 226. 227. 228. 229. 230. 231. 232. 233. 234. 235. 236. 237. 238. 239. 240. 241. 242. 243. 244. 245. 246. 247. 248. 249. 250. 251. 252. 253. 254. 255. 256. 257. 258. 259. 260. 261. 262. 263. 264. 265. 266. 267. 268. 269. 270. 271. 272. 273. 274. 275. 276. 277. 278. 279. 280. 281. 282. 283. 284. 285. 286. 287. 288. 289. 290. 291. 292. 293. 294. 295. 296. 297. 298. 299. 300. 301. 302. 303. 304. 305. 306. 307. 308. 309. 310. 311. 312. 313. 314. 315. 316. 317. 318. 319. 320. 321. 322. 323. 324. 325. 326. 327. 328. 329. 330. 331. 332. 333. 334. 335. 336. 337. 338. 339. 340. 341. 342. 343. 344. 345. 346. 347. 348. 349. 350. 351. 352. 353. 354. 355. 356.
package isc.jcp;
import java.util.*;
import java.io.IOException;
import org.w3c.dom.Element;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import javax.xml.xpath.XPathFactory;
import org.apache.xml.security.exceptions.XMLSecurityException;
import org.apache.ws.security.WSSecurityException;
import java.security.SignatureException;
import java.security.InvalidKeyException;
import java.security.cert.X509Certificate;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateEncodingException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.KeyStoreException;
import java.security.UnrecoverableKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import com.objsys.asn1j.runtime.Asn1Exception;
//import javax.swing.JFrame;
//import javax.swing.JOptionPane;
/**
* Фасад для работы с JCP из веб-сервисов Cache.
*/
public class JcpFacade
{
private static final String ENVELOPE_NS_URI = "http://schemas.xmlsoap.org/soap/envelope/";
private static final String WSSE_NS_URI = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
private static final String DS_NS_URI = "http://www.w3.org/2000/09/xmldsig#";
private static XPathFactory xpathFactory = XPathFactory.newInstance();
/**
* Формирует ЭЦП в формате XML Signature (ds:Signature).
*
* @param xmlFragmentBytes XML-документ, элемент которого подписывается; передается в виде массива байт в кодировке UTF-8
* @param wsuId значение атрибута wsu:Id подписываемаего элемента
* @param certFilename имя файла сертификата в формате X.509, соответствующего секретному ключу
* @param keyPassword пароль для доступа к секретному ключу
* @return Строка, содержащая XML-элемент ds:Signature.
* @throws XMLSecurityException
* @throws IOException
* @throws CertificateException
* @throws KeyStoreException
* @throws NoSuchAlgorithmException
* @throws UnrecoverableKeyException
*/
public static String createSignature(byte[] xmlFragmentBytes, String wsuId, String certFilename, String keyPassword, String StoreName)
throws XMLSecurityException, IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException
{
String xmlFragment = new String(xmlFragmentBytes, "UTF-8");
JcpUtils.initJcp();
if (StoreName == null)
{
throw new RuntimeException("Не задано имя хранилища");
}
//String storename = JcpUtils.getStoreName("c:\\store.cfg");
//JcpUtils.ShowMessage(storename);
KeyStore keyStore = JcpUtils.getFloppyStore(StoreName,keyPassword);
if (keyStore == null)
{
throw new RuntimeException("Не удалось получить доступ к хранилищу ключей " + StoreName);
}
//Test(keyStore);
//JcpUtils.ShowMessage("Получение сертификата");
X509Certificate certificate = JcpUtils.getCertificate(certFilename);
if (certificate == null)
{
// JcpUtils.ShowMessage("Не смогли получить");
throw new RuntimeException("Не найден сертификат");
}
//JcpUtils.ShowMessage("Получение закрытого ключа");
PrivateKey privateKey = getPrivateKey(keyStore, certificate, keyPassword, certFilename);
if (privateKey == null)
{
throw new RuntimeException("Не найден закрытый ключ");
}
//JcpUtils.ShowMessage("Работа с xml");
Document document = XmlUtils.deserialize(xmlFragment);
IdAttrResourceResolver resolver;
synchronized(xpathFactory)
{
resolver = new IdAttrResourceResolver(xpathFactory);
}
Element signature = JcpUtils.signDocuments(
document,
new String[] {"#" + wsuId},
resolver,
certificate,
privateKey);
return XmlUtils.serializeNode(signature);
}
/**
* Проверяет валидность ЭЦП для SOAP-сообщения.
*
* @param soapEnvelopeBytes подписанное SOAP-сообщение; передается в виде массива байт в кодировке UTF-8
* @return Boolean
* @throws XMLSecurityException
* @throws IOException
* @throws WSSecurityException
* @throws CertificateException
*/
public static Boolean verifySignature(byte[] soapEnvelopeBytes)
throws XMLSecurityException, IOException, WSSecurityException, CertificateException
{
String soapEnvelope = new String(soapEnvelopeBytes, "UTF-8");
//FileOutputStream f = new FileOutputStream("C://Temp//verifySignature.xml");
//f.write(soapEnvelopeBytes);
//f.flush();
Document envelopeDocument = XmlUtils.deserialize(soapEnvelope);
Element header = findSoapHeader(envelopeDocument);
if (header == null)
throw new RuntimeException("Не найден элемент SOAP Header");
NodeList securityNL = header.getElementsByTagNameNS(WSSE_NS_URI, "Security");
if (securityNL == null || securityNL.getLength() == 0)
{
throw new RuntimeException("Не найден элемент WS-Security");
}
IdAttrResourceResolver resolver;
synchronized(xpathFactory)
{
resolver = new IdAttrResourceResolver(xpathFactory);
}
JcpUtils.initJcp();
int signaturesVerified = 0;
for (int i = 0; i < securityNL.getLength(); i++)
{
Element signature = getSignatureElement((Element)securityNL.item(i));
if (signature == null) continue;
if (!JcpUtils.verifySignature(signature, resolver))
{
signaturesVerified = -1;
break;
}
signaturesVerified++;
}
if (signaturesVerified == 0)
{
throw new RuntimeException("Не найден элемент WS-Security, содержащий элемент Signature");
}
return Boolean.valueOf(signaturesVerified > -1);
}
private static Element findSoapHeader(Document envelopeDocument)
{
Element header = null;
Element envelope = envelopeDocument.getDocumentElement();
if (!"Envelope".equals(envelope.getLocalName()) || !ENVELOPE_NS_URI.equals(envelope.getNamespaceURI()))
throw new RuntimeException("Не найден элемент SOAP Envelope");
Element body = XmlUtils.getFirstChildElement(envelope);
if (body == null || !ENVELOPE_NS_URI.equals(body.getNamespaceURI()))
throw new RuntimeException("Не найдены элементы SOAP Header / SOAP Body");
if ("Header".equals(body.getLocalName()))
{
header = body;
body = XmlUtils.getNextChildElement(envelope, header);
if (body == null || !ENVELOPE_NS_URI.equals(body.getNamespaceURI()))
throw new RuntimeException("Не найден элемент SOAP Body");
}
if (!"Body".equals(body.getLocalName()))
throw new RuntimeException("Не найден элемент SOAP Body");
return header;
}
private static Element getSignatureElement(Element security)
{
NodeList sigNL = security.getElementsByTagNameNS(DS_NS_URI, "Signature");
if (sigNL == null || sigNL.getLength() == 0)
{
return null;
}
else if (sigNL.getLength() > 1)
{
throw new RuntimeException("Найдено несколько элементов Signature в рамках одного элемента Security");
}
else
{
return (Element)sigNL.item(0);
}
}
private static PrivateKey getPrivateKey(KeyStore keyStore, X509Certificate certificate, String password, String certFilename)
throws KeyStoreException, CertificateEncodingException, NoSuchAlgorithmException, UnrecoverableKeyException
{
PrivateKey result = null;
Enumeration aliases = keyStore.aliases();
String alias = JcpUtils.getAlias(certFilename);
if (alias == null) {
while (aliases.hasMoreElements())
{
alias = (String)aliases.nextElement();
if (keyStore.isKeyEntry(alias))
{
Key key = getKey(keyStore, alias, password);
if (key instanceof PrivateKey)
{
result = (PrivateKey)key;
X509Certificate floppyCertificate = (X509Certificate)keyStore.getCertificate(alias);
if (floppyCertificate != null)
{
if (Arrays.equals(certificate.getEncoded(), floppyCertificate.getEncoded()))
return result;
else
result = null;
}
}
}
}
}
else
{
if (keyStore.isKeyEntry(alias))
{
Key key = getKey(keyStore, alias, password);
if (key instanceof PrivateKey)
{
result = (PrivateKey)key;
X509Certificate floppyCertificate = (X509Certificate)keyStore.getCertificate(alias);
if (floppyCertificate != null)
{
if (Arrays.equals(certificate.getEncoded(), floppyCertificate.getEncoded()))
return result;
else
result = null;
}
}
}
}
if ((keyStore.size() == 1) && (result != null))
return result;
else
return null;
}
private static Key getKey(KeyStore keyStore, String Alias, String Password)
throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException
{
Key key;
if (Password != null)
{
key = keyStore.getKey(Alias, Password.toCharArray());
}
else
{
key = keyStore.getKey(Alias, null);
}
return key;
}
/**
* Формирует ЭЦП для произвольного массива байт.
*
* @param data подписываемый массив байт
* @param certFilename имя файла сертификата в формате X.509, соответствующего секретному ключу
* @param keyPassword пароль для доступа к секретному ключу
* @return ЭЦП
* @throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, SignatureException, Asn1Exception, CertificateEncodingException, InvalidKeyException
*/
public static byte[] createCMSSignature(byte[] data, String certFilename, String keyPassword, String StoreName)
throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, SignatureException, Asn1Exception, CertificateEncodingException, InvalidKeyException
{
JcpUtils.initJcp();
if (StoreName == null)
{
throw new RuntimeException("Не задано имя хранилища");
}
//String StoreName = JcpUtils.getStoreName("c:\\store.cfg");
KeyStore keyStore = JcpUtils.getFloppyStore(StoreName, keyPassword);
if (keyStore == null) throw new RuntimeException("Не удалось получить доступ к хранилищу ключей "+StoreName);
X509Certificate certificate = JcpUtils.getCertificate(certFilename);
if (certificate == null) throw new RuntimeException("Не найден сертификат");
PrivateKey privateKey = getPrivateKey(keyStore, certificate, keyPassword, certFilename);
if (privateKey == null) throw new RuntimeException("Не найден закрытый ключ");
return JcpUtils.createCMS(data, new PrivateKey[] { privateKey }, new Certificate[] { certificate }, true);
}
/**
* Проверка CMS подписи массива байт.
*
* @param cmsBytes CMS подпись
* @param data подписанные данные; null = поверяются подписанные данные, содержащиеся внутри CMS; если имеются вложенные в CMS подписанные данные, то data игнорируется
* @param certFilename имя файла сертификата в формате X.509; null = использовать сертификат, содержащийся в CMS; если имеются вложенные в CMS сертификаты, то certFilename игнорируется
* @return верна ли подпись
* @throws IOException, SignatureException, Asn1Exception, NoSuchAlgorithmException, InvalidKeyException, CertificateException, KeyStoreException
*/
public static Boolean verifyCMSSignature(byte[] cmsBytes, byte[] data, String certFilename)
throws IOException, SignatureException, Asn1Exception, NoSuchAlgorithmException, InvalidKeyException, CertificateException, KeyStoreException
{
X509Certificate certificate = null;
if (certFilename != null)
{
certificate = JcpUtils.getCertificate(certFilename);
if (certificate == null) {
throw new RuntimeException("Не найден сертификат");
}
}
JcpUtils.initJcp();
return Boolean.valueOf(JcpUtils.verifyCMS(cmsBytes, certificate == null ? null : new Certificate[] { certificate }, data));
}
/**
*/
public static byte[] getDigest(byte[] data)
throws IOException, NoSuchAlgorithmException
{
JcpUtils.initJcp();
return JcpUtils.getDigest(data);
}
}
и
JcpUtils 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144. 145. 146. 147. 148. 149. 150. 151. 152. 153. 154. 155. 156. 157. 158. 159. 160. 161. 162. 163. 164. 165. 166. 167. 168. 169. 170. 171. 172. 173. 174. 175. 176. 177. 178. 179. 180. 181. 182. 183. 184. 185. 186. 187. 188. 189. 190. 191. 192. 193. 194. 195. 196. 197. 198. 199. 200. 201. 202. 203. 204. 205. 206. 207. 208. 209. 210. 211. 212. 213. 214. 215. 216. 217. 218. 219. 220. 221. 222. 223. 224. 225. 226. 227. 228. 229. 230. 231. 232. 233. 234. 235. 236. 237. 238. 239. 240. 241. 242. 243. 244. 245. 246. 247. 248. 249. 250. 251. 252. 253. 254. 255. 256. 257. 258. 259. 260. 261. 262. 263. 264. 265. 266. 267. 268. 269. 270. 271. 272. 273. 274. 275. 276. 277. 278. 279. 280. 281. 282. 283. 284. 285. 286. 287. 288. 289. 290. 291. 292. 293. 294. 295. 296. 297. 298. 299. 300. 301. 302. 303. 304. 305. 306. 307. 308. 309. 310. 311. 312. 313. 314. 315. 316. 317. 318. 319. 320. 321. 322. 323. 324. 325. 326. 327. 328. 329. 330. 331. 332. 333. 334. 335. 336. 337. 338. 339. 340. 341. 342. 343. 344. 345. 346. 347. 348. 349. 350. 351. 352. 353. 354. 355. 356. 357. 358. 359. 360. 361. 362. 363. 364. 365. 366. 367. 368. 369. 370. 371. 372. 373. 374. 375. 376. 377. 378. 379. 380. 381. 382. 383. 384. 385. 386. 387. 388. 389. 390. 391. 392. 393. 394. 395. 396. 397. 398. 399. 400. 401. 402. 403. 404. 405. 406. 407. 408. 409. 410. 411. 412. 413. 414. 415. 416. 417. 418. 419. 420. 421. 422. 423. 424. 425. 426. 427. 428. 429. 430. 431. 432. 433. 434. 435. 436. 437. 438. 439. 440. 441. 442. 443. 444. 445. 446. 447. 448. 449. 450. 451. 452. 453. 454. 455. 456. 457. 458. 459. 460. 461. 462. 463. 464. 465. 466. 467. 468. 469. 470. 471. 472. 473. 474. 475. 476. 477. 478. 479. 480. 481. 482. 483. 484. 485. 486. 487. 488. 489. 490. 491. 492. 493. 494. 495. 496. 497. 498. 499. 500. 501. 502. 503. 504. 505. 506. 507. 508. 509. 510. 511. 512. 513. 514. 515. 516. 517. 518. 519. 520. 521. 522. 523. 524. 525. 526. 527. 528. 529. 530. 531. 532. 533. 534. 535. 536. 537. 538. 539. 540. 541. 542. 543. 544. 545. 546. 547. 548. 549. 550. 551. 552. 553. 554. 555. 556. 557. 558. 559. 560. 561. 562. 563. 564. 565. 566. 567. 568. 569. 570. 571. 572. 573. 574. 575. 576. 577. 578. 579. 580. 581. 582. 583. 584. 585. 586. 587. 588. 589. 590. 591. 592. 593. 594. 595. 596. 597. 598. 599. 600. 601. 602. 603. 604. 605. 606. 607. 608. 609. 610. 611. 612. 613. 614. 615. 616. 617. 618. 619. 620. 621. 622. 623. 624. 625. 626. 627. 628. 629. 630. 631. 632. 633. 634. 635. 636. 637. 638. 639. 640. 641. 642. 643. 644. 645. 646. 647. 648. 649. 650. 651. 652. 653. 654. 655. 656. 657. 658. 659. 660. 661. 662. 663. 664. 665. 666. 667. 668. 669. 670. 671. 672.
package isc.jcp;
import java.util.*;
import java.io.*;
import org.w3c.dom.Element;
import org.w3c.dom.Document;
import java.security.DigestInputStream;
import java.security.Security;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.MessageDigest;
import java.security.Signature;
import java.security.SignatureException;
import java.security.InvalidKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateEncodingException;
import org.apache.xml.security.Init;
import org.apache.xml.security.c14n.Canonicalizer;
import org.apache.xml.security.utils.resolver.ResourceResolverSpi;
import org.apache.xml.security.keys.KeyInfo;
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.exceptions.XMLSecurityException;
import org.apache.xml.security.transforms.Transforms;
import org.apache.ws.security.message.token.SecurityTokenReference;
import org.apache.ws.security.WSDocInfo;
import org.apache.ws.security.message.token.X509Security;
import org.apache.ws.security.WSSecurityException;
import ru.CryptoPro.JCP.JCP;
import ru.CryptoPro.JCP.params.OID;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.CMSVersion;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.CertificateChoices;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.CertificateSet;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.ContentInfo;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.DigestAlgorithmIdentifier;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.DigestAlgorithmIdentifiers;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.EncapsulatedContentInfo;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.IssuerAndSerialNumber;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.SignatureAlgorithmIdentifier;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.SignatureValue;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.SignedData;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.SignerIdentifier;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.SignerInfo;
import ru.CryptoPro.JCP.ASN.CryptographicMessageSyntax.SignerInfos;
import ru.CryptoPro.JCP.ASN.PKIX1Explicit88.Attribute;
import ru.CryptoPro.JCP.ASN.PKIX1Explicit88.CertificateSerialNumber;
import ru.CryptoPro.JCP.ASN.PKIX1Explicit88.Name;
import ru.CryptoPro.JCP.tools.Array;
import com.objsys.asn1j.runtime.Asn1Type;
import com.objsys.asn1j.runtime.Asn1BerDecodeBuffer;
import com.objsys.asn1j.runtime.Asn1BerEncodeBuffer;
import com.objsys.asn1j.runtime.Asn1Null;
import com.objsys.asn1j.runtime.Asn1ObjectIdentifier;
import com.objsys.asn1j.runtime.Asn1OctetString;
import com.objsys.asn1j.runtime.Asn1Exception;
import java.security.UnrecoverableKeyException;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
/**
* Контейнер для полезных методов работы с КриптоПро JCP.
*/
public class JcpUtils
{
/** Алгоритм подписи (ГОСТ Р 34.10-2001) **/
public static final String signMethod = "http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411";
/** Алгоритм хеширования, используемый при подписи (ГОСТ Р 34.11-94) **/
public static final String digestMethod = "http://www.w3.org/2001/04/xmldsig-more#gostr3411";
private static final String STR_CMS_OID_SIGNED = "1.2.840.113549.1.7.2";
private static final String DIGEST_OID = JCP.GOST_DIGEST_OID;
private static final String STR_CMS_OID_DATA = "1.2.840.113549.1.7.1";
private static final String SIGN_OID = JCP.GOST_EL_KEY_OID;
private static final String STR_CMS_OID_CONT_TYP_ATTR = "1.2.840.113549.1.9.3";
private static final String STR_CMS_OID_DIGEST_ATTR = "1.2.840.113549.1.9.4";
private static final String DIGEST_ALG_NAME = JCP.GOST_DIGEST_NAME;
/** Хранилище ключей типа FloppyStore **/
private static KeyStore floppyStore;
/** Кэш сертификатов **/
private static Map certificates = new HashMap();
/** Фабрика сертификатов **/
private static CertificateFactory certificateFactory;
/**
* Инициализирует JCP и XML Security.
*/
public synchronized static void initJcp()
{
ru.CryptoPro.JCP.JCP jcp = new ru.CryptoPro.JCP.JCP();
if (Security.getProvider(jcp.getName()) == null)
{
Security.addProvider(jcp);
}
if (!ru.CryptoPro.JCPxml.xmldsig.JCPXMLDSigInit.isInitialized())
{
ru.CryptoPro.JCPxml.xmldsig.JCPXMLDSigInit.init();
}
if (!Init.isInitialized())
{
Init.init();
}
}
/*
* Вернет имя хранилищиа
*/
public static String getStoreName(String file)
throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException
{
String str = "";
try {
BufferedReader in = new BufferedReader(new FileReader(file));
while ((str = in.readLine()) != null) {
//JOptionPane.showMessageDialog(frame, str);
if (!"".equals(str)) {
break;
}
}
in.close();
} catch (IOException e) {}
if ("".equals(str)) {
str = "FloppyStore";
}
//JOptionPane.showMessageDialog(frame, str);
return str;
}
/**
* Возвращает ссылку на хранилище ключей FloppyStore.
*
* @return KeyStore
* @throws IOException
* @throws CertificateException
* @throws KeyStoreException
* @throws NoSuchAlgorithmException
*/
public static KeyStore getFloppyStore(String StoreName, String keyPassword )
throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException
{
if (floppyStore == null)
initFloppyStore(StoreName, keyPassword);
return floppyStore;
}
/**
* Инициализирует хранилище ключей FloppyStore.
*
* @throws IOException
* @throws CertificateException
* @throws KeyStoreException
* @throws NoSuchAlgorithmException
*/
private synchronized static void initFloppyStore(String StoreName, String keyPassword )
throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException
{
floppyStore = KeyStore.getInstance(StoreName);
if (floppyStore != null)
{
if (keyPassword == null) {
floppyStore.load(null, null);
}
else {
floppyStore.load(null, keyPassword.toCharArray());
}
}
/*
*/
}
/**
* Загружает сертификат в формате X.509 из потока.
*
* @param is поток, содержащий сертификат в формате X.509
* @return X509Certificate
* @throws CertificateException
*/
public synchronized static X509Certificate getCertificate(InputStream is)
throws CertificateException
{
if (certificateFactory == null)
certificateFactory = CertificateFactory.getInstance("X.509");
X509Certificate cert = null;
try
{
cert = (X509Certificate)certificateFactory.generateCertificate(new BufferedInputStream(is));
}
finally
{
try
{
is.close();
}
catch (IOException ignore)
{}
}
return cert;
}
/**
* Загружает сертификат в формате X.509 из файла. Использует кэш сертификатов.
*
* @param file имя файла, содержащего сертификат в формате X.509
* @return X509Certificate
* @throws FileNotFoundException
* @throws CertificateException
*/
public synchronized static X509Certificate getCertificate(String file)
throws CertificateException, KeyStoreException, UnsupportedEncodingException
{
X509Certificate cert = null;
if (file != null) {
String alias = getAlias(file);
if (alias == null) {
try {
FileInputStream ifStream = new FileInputStream(file);
if (certificates.containsKey(file)) {
return (X509Certificate)certificates.get(file);
}
cert = getCertificate(ifStream);
}
catch(FileNotFoundException ignore)
{ }
if (cert != null) {
certificates.put(file, cert);
return cert;
}
}
else {
cert = (X509Certificate) floppyStore.getCertificate(alias);
}
}
return cert;
}
// Получить алиас
public static String getAlias(String fileoralias)
throws KeyStoreException
{
if (fileoralias == null) return null;
Enumeration aliasesEnum = floppyStore.aliases();
String result = null;
while (aliasesEnum.hasMoreElements()) {
String alias = aliasesEnum.nextElement().toString();
if (alias.indexOf(fileoralias)!= -1) {
result = alias;
break;
}
}
return result;
}
// Просто функция ShowMessage
public static void ShowMessage(String Message)
{
JFrame frame=new JFrame();
JOptionPane.showMessageDialog(frame, Message);
}
/**
* Проверяет валидность ЭЦП.
*
* @param signatureElement XML-элемент ds:Signature
* @param resourceResolver реализация <code>org.apache.xml.security.utils.resolver.ResourceResolverSpi</code>, используемая при проверке подписи
* @return boolean
* @throws XMLSecurityException
* @throws WSSecurityException
* @throws CertificateException
*/
public static boolean verifySignature(Element signatureElement, ResourceResolverSpi resourceResolver)
throws XMLSecurityException, WSSecurityException, CertificateException
{
XMLSignature signature = new XMLSignature(signatureElement, "");
if (signature.getSignedInfo().getLength() == 0)
throw new RuntimeException("No signed resources");
signature.addResourceResolver(resourceResolver);
KeyInfo ki = signature.getKeyInfo();
if (ki == null)
throw new RuntimeException("KeyInfo element not found");
else if (ki.isEmpty())
throw new RuntimeException("Empty KeyInfo element");
else if (ki.containsX509Data())
return signature.checkSignatureValue(ki.getX509Certificate());
else if (ki.getPublicKey() != null)
return signature.checkSignatureValue(ki.getPublicKey());
// далее - сложный случай
Element kiChild = XmlUtils.getFirstChildElement(ki.getElement());
if (kiChild == null) throw new RuntimeException("Empty KeyInfo element");
SecurityTokenReference tref = new SecurityTokenReference(kiChild);
if (!tref.containsReference() || (tref.getReference() == null))
throw new RuntimeException("SecurityTokenReference does not contain a direct reference (i.e. <wsse:Reference> element)");
else if (!X509Security.X509_V3_TYPE.equals(tref.getReference().getValueType()))
throw new RuntimeException("Reference value type \"" + tref.getReference().getValueType() + "\" is not supported");
Element tokenEl = tref.getTokenElement(signatureElement.getOwnerDocument(), new WSDocInfo(signatureElement.getOwnerDocument()), null);
X509Security token = new X509Security(tokenEl);
X509Certificate cert = getCertificate(new ByteArrayInputStream(token.getToken()));
return signature.checkSignatureValue(cert);
}
/**
* Формирует ЭЦП в формате XML Signature (ds:Signature).
*
* @param targetDoc XML-документ (DOM), элементы которого подписываются
* @param uris массив ссылок (URI) на подписываемые элементы
* @param resourceResolver реализация <code>org.apache.xml.security.utils.resolver.ResourceResolverSpi</code>, используемая при формировании подписи
* @param certificate сертификат в формате X.509, соответствующий секретному ключу, используемому при формировании подписи
* @param privateKey секретный ключ, используемый при формировании подписи
* @return XML-элемент ds:Signature
* @throws XMLSecurityException
*/
public static Element signDocuments(Document targetDoc, String[] uris, ResourceResolverSpi resourceResolver, X509Certificate certificate, PrivateKey privateKey)
throws XMLSecurityException
{
XMLSignature sig = new XMLSignature(targetDoc, "", signMethod, Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
Transforms transforms = new Transforms(targetDoc);
transforms.addTransform(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS);
for (int i = 0; i < uris.length; i++)
sig.addDocument(uris[i], transforms, digestMethod);
sig.getSignedInfo().addResourceResolver(resourceResolver);
sig.addKeyInfo(certificate);
sig.sign(privateKey);
return sig.getElement();
}
/**
* Формирует ЭЦП для произвольного массива байт.
*
* @param data подписываемый массив байт
* @param keys массив секретных ключей, используемый при формировании подписи
* @param certs массив сертификатов в формате X.509, соответствующий массиву секретных ключей
* @param detached признак необходимости создания detached ЭЦП - см. http://notary.cryptopro.ru/Notary_Help.htm
* @return ЭЦП
* @throws IOException, SignatureException, Asn1Exception, CertificateEncodingException, NoSuchAlgorithmException, InvalidKeyException
*/
public static byte[] createCMS(byte[] data, PrivateKey[] keys, Certificate[] certs, boolean detached)
throws IOException, SignatureException, Asn1Exception, CertificateEncodingException, NoSuchAlgorithmException, InvalidKeyException
{
//create CMS
final SignedData cms = new SignedData();
cms.version = new CMSVersion(1);
final ContentInfo all = new ContentInfo();
all.contentType = new Asn1ObjectIdentifier(new OID(STR_CMS_OID_SIGNED).value);
all.content = cms;
// digest
final DigestAlgorithmIdentifier a = new DigestAlgorithmIdentifier(new OID(DIGEST_OID).value);
a.parameters = new Asn1Null();
cms.digestAlgorithms = new DigestAlgorithmIdentifiers(1);
cms.digestAlgorithms.elements[0] = a;
if (detached)
cms.encapContentInfo = new EncapsulatedContentInfo(new Asn1ObjectIdentifier(new OID(STR_CMS_OID_DATA).value), null);
else
cms.encapContentInfo = new EncapsulatedContentInfo(new Asn1ObjectIdentifier(new OID(STR_CMS_OID_DATA).value), new Asn1OctetString(data));
// certificates
final int ncerts = certs.length;
cms.certificates = new CertificateSet(ncerts);
cms.certificates.elements = new CertificateChoices[ncerts];
for (int i = 0; i < cms.certificates.elements.length; i++)
{
final ru.CryptoPro.JCP.ASN.PKIX1Explicit88.Certificate certificate = new ru.CryptoPro.JCP.ASN.PKIX1Explicit88.Certificate();
final Asn1BerDecodeBuffer decodeBuffer = new Asn1BerDecodeBuffer(certs[i].getEncoded());
certificate.decode(decodeBuffer);
cms.certificates.elements[i] = new CertificateChoices();
cms.certificates.elements[i].set_certificate(certificate);
}
// Signature.getInstance
final Signature signature = Signature.getInstance(JCP.GOST_EL_SIGN_NAME);
byte[] sign;
// signer infos
final int nsign = keys.length;
cms.signerInfos = new SignerInfos(nsign);
for (int i = 0; i < cms.signerInfos.elements.length; i++)
{
signature.initSign(keys[i]);
signature.update(data);
sign = signature.sign();
final CertificateSerialNumber num = new CertificateSerialNumber(((X509Certificate)certs[i]).getSerialNumber());
final byte[] encodedName = ((X509Certificate)certs[i]).getIssuerX500Principal().getEncoded();
final Asn1BerDecodeBuffer nameBuf = new Asn1BerDecodeBuffer(encodedName);
final Name name = new Name();
name.decode(nameBuf);
cms.signerInfos.elements[i] = new SignerInfo();
cms.signerInfos.elements[i].version = new CMSVersion(1);
cms.signerInfos.elements[i].sid = new SignerIdentifier();
cms.signerInfos.elements[i].sid.set_issuerAndSerialNumber(new IssuerAndSerialNumber(name, num));
cms.signerInfos.elements[i].digestAlgorithm = new DigestAlgorithmIdentifier(new OID(DIGEST_OID).value);
cms.signerInfos.elements[i].digestAlgorithm.parameters = new Asn1Null();
cms.signerInfos.elements[i].signatureAlgorithm = new SignatureAlgorithmIdentifier(new OID(SIGN_OID).value);
cms.signerInfos.elements[i].signatureAlgorithm.parameters = new Asn1Null();
cms.signerInfos.elements[i].signature = new SignatureValue(sign);
}
// encode
final Asn1BerEncodeBuffer asnBuf = new Asn1BerEncodeBuffer();
all.encode(asnBuf, true);
return asnBuf.getMsgCopy();
}
/**
* Проверка CMS подписи массива байт.
*
* @param cmsBytes CMS подпись
* @param certs массив сертификатов в формате X.509; null = использовать сертификат, содержащийся в CMS; если имеются вложенные в CMS сертификаты, то certs игнорируется
* @param data подписанные данные; null = поверяются подписанные данные, содержащиеся внутри CMS; если имеются вложенные в CMS подписанные данные, то data игнорируется
* @return верна ли подпись
* @throws IOException, SignatureException, Asn1Exception, NoSuchAlgorithmException, InvalidKeyException, CertificateException
*/
public static boolean verifyCMS(byte[] cmsBytes, Certificate[] certs, byte[] data)
throws IOException, SignatureException, Asn1Exception, NoSuchAlgorithmException, InvalidKeyException, CertificateException
{
int validsign = 0;
final Asn1BerDecodeBuffer asnBuf = new Asn1BerDecodeBuffer(cmsBytes);
final ContentInfo all = new ContentInfo();
all.decode(asnBuf);
if (!new OID(STR_CMS_OID_SIGNED).eq(all.contentType.value)) throw new RuntimeException("Формат подписи не поддерживается");
final SignedData cms = (SignedData)all.content;
final byte[] text;
if (cms.encapContentInfo.eContent != null)
text = cms.encapContentInfo.eContent.value;
else if (data != null)
text = data;
else
throw new RuntimeException("Нет данных для проверки подписи");
OID digestOid = null;
final DigestAlgorithmIdentifier digestAlgorithmIdentifier = new DigestAlgorithmIdentifier(new OID(DIGEST_OID).value);
for (int i = 0; i < cms.digestAlgorithms.elements.length; i++)
{
if (cms.digestAlgorithms.elements[i].algorithm.equals(digestAlgorithmIdentifier.algorithm))
{
digestOid = new OID(cms.digestAlgorithms.elements[i].algorithm.value);
break;
}
}
if (digestOid == null) throw new RuntimeException("Неизвестный дайджест");
final OID eContTypeOID = new OID(cms.encapContentInfo.eContentType.value);
if (cms.certificates != null)
{
//Проверка на вложенных сертификатах
for (int i = 0; i < cms.certificates.elements.length; i++)
{
final Asn1BerEncodeBuffer encBuf = new Asn1BerEncodeBuffer();
cms.certificates.elements[i].encode(encBuf);
final CertificateFactory cf = CertificateFactory.getInstance("X.509");
final X509Certificate cert = (X509Certificate)cf.generateCertificate(encBuf.getInputStream());
for (int j = 0; j < cms.signerInfos.elements.length; j++)
{
final SignerInfo info = cms.signerInfos.elements[j];
if (!digestOid.equals(new OID(info.digestAlgorithm.algorithm.value))) throw new RuntimeException("Подпись не соответствует сертификату");
final boolean checkResult = verifyOnCert(cert, cms.signerInfos.elements[j], text, eContTypeOID);
if (checkResult) validsign += 1;
}
}
}
else if (certs != null)
{
//Проверка на указанных сертификатах
for (int i = 0; i < certs.length; i++)
{
final X509Certificate cert = (X509Certificate)certs[i];
for (int j = 0; j < cms.signerInfos.elements.length; j++)
{
final SignerInfo info = cms.signerInfos.elements[j];
if (!digestOid.equals(new OID(info.digestAlgorithm.algorithm.value))) throw new RuntimeException("Подпись не соответствует сертификату");
final boolean checkResult = verifyOnCert(cert, cms.signerInfos.elements[j], text, eContTypeOID);
if (checkResult) validsign += 1;
}
}
}
else
{
// Certificates for validation not found
}
return (cms.signerInfos.elements.length == validsign);
}
/**
* Попытка проверки подписи на указанном сертификате
*
* @param cert сертификат для проверки
* @param text текст для проверки
* @param info подпись
* @param eContentTypeOID
* @return верна ли подпись
* @throws IOException, SignatureException, Asn1Exception, NoSuchAlgorithmException, InvalidKeyException
*/
private static boolean verifyOnCert(X509Certificate cert, SignerInfo info, byte[] text, OID eContentTypeOID)
throws IOException, SignatureException, Asn1Exception, NoSuchAlgorithmException, InvalidKeyException
{
//подпись
final byte[] sign = info.signature.value;
//данные для проверки подписи
final byte[] data;
if (info.signedAttrs == null)
{
//аттрибуты подписи отсутствуют
data = text;
}
else
{
//присутствуют аттрибуты подписи (SignedAttr)
final Attribute[] signAttrElem = info.signedAttrs.elements;
//проверка аттрибута content-type
final Asn1ObjectIdentifier contentTypeOid = new Asn1ObjectIdentifier((new OID(STR_CMS_OID_CONT_TYP_ATTR)).value);
Attribute contentTypeAttr = null;
for (int r = 0; r < signAttrElem.length; r++)
{
final Asn1ObjectIdentifier oid = signAttrElem[r].type;
if (oid.equals(contentTypeOid)) contentTypeAttr = signAttrElem[r];
}
if (contentTypeAttr == null)
throw new RuntimeException("Отсутствует атрибут, отвечающий за структуру подписи");
if (!contentTypeAttr.values.elements[0].equals(new Asn1ObjectIdentifier(eContentTypeOID.value)))
throw new RuntimeException("Недопустимая структура подписи");
//проверка аттрибута message-digest
final Asn1ObjectIdentifier messageDigestOid = new Asn1ObjectIdentifier((new OID(STR_CMS_OID_DIGEST_ATTR)).value);
Attribute messageDigestAttr = null;
for (int r = 0; r < signAttrElem.length; r++)
{
final Asn1ObjectIdentifier oid = signAttrElem[r].type;
if (oid.equals(messageDigestOid)) messageDigestAttr = signAttrElem[r];
}
if (messageDigestAttr == null)
throw new RuntimeException("Не найдено значение дайджеста");
//вычисление messageDigest
final ByteArrayInputStream stream = new ByteArrayInputStream(text);
final MessageDigest digest = MessageDigest.getInstance(DIGEST_ALG_NAME);
final DigestInputStream digestStream = new DigestInputStream(stream, digest);
while (digestStream.available() != 0)
digestStream.read();
final Asn1Type open = messageDigestAttr.values.elements[0];
final Asn1OctetString hash = (Asn1OctetString)open;
if (!Array.toHexString(digest.digest()).equals(Array.toHexString(hash.value)))
throw new RuntimeException("Недопустимое значение дайджеста");
//данные для проверки подписи
final Asn1BerEncodeBuffer encBufSignedAttr = new Asn1BerEncodeBuffer();
info.signedAttrs.encode(encBufSignedAttr);
data = encBufSignedAttr.getMsgCopy();
}
// проверка подписи
final Signature signature = Signature.getInstance(JCP.GOST_EL_SIGN_NAME);
signature.initVerify(cert);
signature.update(data);
return signature.verify(sign);
}
public static byte[] getBytesFromFile(File file) throws IOException {
InputStream is = new FileInputStream(file);
long length = file.length();
if (length > Integer.MAX_VALUE) {
return null;
}
byte[] bytes = new byte[(int)length];
// Read in the bytes
int offset = 0;
int numRead = 0;
while (offset < bytes.length && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
offset += numRead;
}
// Ensure all the bytes have been read in
if (offset < bytes.length) {
throw new IOException("Could not completely read file "+file.getName());
}
// Close the input stream and return bytes
is.close();
return bytes;
}
/**
* Метод печатает список алиасов
* @throws KeyStoreException
* @throws NoSuchAlgorithmException
* @throws UnrecoverableKeyException
*/
public static void prnListAlias(String StoreName, String keyPassword)
throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException, IOException, CertificateException
{
initJcp();
getFloppyStore(StoreName,keyPassword);
try {
Enumeration aliases = floppyStore.aliases();
while (aliases.hasMoreElements())
{
String alias = (String)aliases.nextElement();
System.out.print("alias: " + alias);
System.out.println("");
}
}
catch (Exception ex) {}
floppyStore = null;
}
/**
* Метод возвращает значение хеш для строки text
* @param text принимает входную строку, для которой необходимо вычислить хеш
* @return возвращает хеш
*/
public static byte[] getDigest(byte[] text)
throws IOException, NoSuchAlgorithmException
{
//вычисление messageDigest
final ByteArrayInputStream stream = new ByteArrayInputStream(text);
final MessageDigest digest;
digest = MessageDigest.getInstance(DIGEST_ALG_NAME);
final DigestInputStream digestStream;
digestStream = new DigestInputStream(stream, digest);
while (digestStream.available() != 0) {
digestStream.read();
}
//final Asn1Type open = messageDigestAttr.values.elements[0];
//final Asn1OctetString hash = (Asn1OctetString)open;
//if (!Array.toHexString(digest.digest()).equals(Array.toHexString(hash.value)))
// throw new RuntimeException("Недопустимое значение дайджеста");
return digest.digest();
//return Array.toHexString(digest.digest());
}
}
Соответственно потом проекции классов незабыть перегенерить.
Основное изменение:
String createSignature(byte[] xmlFragmentBytes, String wsuId, String certFilename, String keyPassword, String StoreName)
Может принимать имя хранилища (StoreName, не только FloppyStore) и путь к файлу сертификата или имя алиаса (certFilename).
Как то так...
|