PageRenderTime 4060ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/projects/jruby-1.7.3/src/org/jruby/ext/openssl/x509store/PEMInputOutput.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 1163 lines | 1001 code | 84 blank | 78 comment | 235 complexity | 22c7f4ea391c54725b73e7a13a089d0c MD5 | raw file
  1. /***** BEGIN LICENSE BLOCK *****
  2. * Version: EPL 1.0/GPL 2.0/LGPL 2.1
  3. *
  4. * The contents of this file are subject to the Common Public
  5. * License Version 1.0 (the "License"); you may not use this file
  6. * except in compliance with the License. You may obtain a copy of
  7. * the License at http://www.eclipse.org/legal/cpl-v10.html
  8. *
  9. * Software distributed under the License is distributed on an "AS
  10. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  11. * implied. See the License for the specific language governing
  12. * rights and limitations under the License.
  13. *
  14. * Copyright (C) 2006 Ola Bini <ola@ologix.com>
  15. * Copyright (C) 2007 William N Dortch <bill.dortch@gmail.com>
  16. *
  17. * Alternatively, the contents of this file may be used under the terms of
  18. * either of the GNU General Public License Version 2 or later (the "GPL"),
  19. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  20. * in which case the provisions of the GPL or the LGPL are applicable instead
  21. * of those above. If you wish to allow use of your version of this file only
  22. * under the terms of either the GPL or the LGPL, and not to allow others to
  23. * use your version of this file under the terms of the EPL, indicate your
  24. * decision by deleting the provisions above and replace them with the notice
  25. * and other provisions required by the GPL or the LGPL. If you do not delete
  26. * the provisions above, a recipient may use your version of this file under
  27. * the terms of any one of the EPL, the GPL or the LGPL.
  28. ***** END LICENSE BLOCK *****/
  29. package org.jruby.ext.openssl.x509store;
  30. import java.io.IOException;
  31. import java.io.Writer;
  32. import java.io.BufferedWriter;
  33. import java.io.BufferedReader;
  34. import java.io.Reader;
  35. import java.io.ByteArrayInputStream;
  36. import java.io.ByteArrayOutputStream;
  37. import java.math.BigInteger;
  38. import java.security.KeyPair;
  39. import java.security.SecureRandom;
  40. import java.security.cert.X509Certificate;
  41. import java.security.cert.X509CRL;
  42. import java.security.cert.CertificateEncodingException;
  43. import java.security.interfaces.DSAPublicKey;
  44. import java.security.interfaces.DSAPrivateKey;
  45. import java.security.interfaces.RSAPublicKey;
  46. import java.security.interfaces.RSAPrivateCrtKey;
  47. import java.util.regex.Matcher;
  48. import java.util.regex.Pattern;
  49. import javax.crypto.spec.DHParameterSpec;
  50. import org.jruby.ext.openssl.OpenSSLReal;
  51. import org.jruby.ext.openssl.impl.PKCS10Request;
  52. import org.bouncycastle.asn1.ASN1Encodable;
  53. import org.bouncycastle.asn1.ASN1Object;
  54. import org.bouncycastle.asn1.ASN1InputStream;
  55. import org.bouncycastle.asn1.ASN1OctetString;
  56. import org.bouncycastle.asn1.ASN1OutputStream;
  57. import org.bouncycastle.asn1.ASN1EncodableVector;
  58. import org.bouncycastle.asn1.ASN1Sequence;
  59. import org.bouncycastle.asn1.ASN1Integer;
  60. import org.bouncycastle.asn1.DEROctetString;
  61. import org.bouncycastle.asn1.DERUTF8String;
  62. import org.bouncycastle.asn1.DLSequence;
  63. import org.bouncycastle.asn1.DERTaggedObject;
  64. import org.bouncycastle.asn1.ASN1ObjectIdentifier;
  65. import org.bouncycastle.asn1.ASN1Primitive;
  66. import org.bouncycastle.asn1.x509.DSAParameter;
  67. import org.bouncycastle.asn1.cms.ContentInfo;
  68. import org.bouncycastle.asn1.pkcs.EncryptionScheme;
  69. import org.bouncycastle.asn1.pkcs.PBES2Parameters;
  70. import org.bouncycastle.asn1.pkcs.PBKDF2Params;
  71. import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
  72. import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
  73. import org.bouncycastle.asn1.pkcs.RC2CBCParameter;
  74. import org.bouncycastle.crypto.BufferedBlockCipher;
  75. import org.bouncycastle.crypto.CipherParameters;
  76. import org.bouncycastle.crypto.InvalidCipherTextException;
  77. import org.bouncycastle.crypto.PBEParametersGenerator;
  78. import org.bouncycastle.crypto.engines.DESedeEngine;
  79. import org.bouncycastle.crypto.engines.RC2Engine;
  80. import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
  81. import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
  82. import org.bouncycastle.crypto.modes.CBCBlockCipher;
  83. import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
  84. import org.bouncycastle.crypto.params.KeyParameter;
  85. import org.bouncycastle.crypto.params.ParametersWithIV;
  86. import org.bouncycastle.util.encoders.Base64;
  87. import org.bouncycastle.util.encoders.Hex;
  88. import org.bouncycastle.cms.CMSSignedData;
  89. import org.bouncycastle.pkcs.PKCS10CertificationRequest;
  90. import java.security.GeneralSecurityException;
  91. import java.security.KeyFactory;
  92. import java.security.NoSuchAlgorithmException;
  93. import java.security.PrivateKey;
  94. import java.security.PublicKey;
  95. import java.security.cert.CertificateFactory;
  96. import java.security.spec.InvalidKeySpecException;
  97. import java.security.spec.KeySpec;
  98. import java.security.spec.PKCS8EncodedKeySpec;
  99. import java.security.spec.RSAPublicKeySpec;
  100. import java.security.spec.X509EncodedKeySpec;
  101. import java.util.StringTokenizer;
  102. import javax.crypto.Cipher;
  103. import javax.crypto.SecretKey;
  104. import javax.crypto.SecretKeyFactory;
  105. import javax.crypto.spec.IvParameterSpec;
  106. import javax.crypto.spec.PBEKeySpec;
  107. import javax.crypto.spec.PBEParameterSpec;
  108. import javax.crypto.spec.SecretKeySpec;
  109. import org.bouncycastle.asn1.ASN1Encoding;
  110. import org.bouncycastle.asn1.ASN1TaggedObject;
  111. import org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
  112. import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
  113. import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
  114. import org.jruby.ext.openssl.Cipher.CipherModule;
  115. import org.jruby.ext.openssl.impl.ASN1Registry;
  116. import org.jruby.ext.openssl.impl.CipherSpec;
  117. /**
  118. * Helper class to read and write PEM files correctly.
  119. *
  120. * @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
  121. */
  122. public class PEMInputOutput {
  123. public static final String BEF = "-----";
  124. public static final String AFT = "-----";
  125. public static final String BEF_G = BEF+"BEGIN ";
  126. public static final String BEF_E = BEF+"END ";
  127. public static final String PEM_STRING_X509_OLD="X509 CERTIFICATE";
  128. public static final String PEM_STRING_X509="CERTIFICATE";
  129. public static final String PEM_STRING_X509_PAIR="CERTIFICATE PAIR";
  130. public static final String PEM_STRING_X509_TRUSTED="TRUSTED CERTIFICATE";
  131. public static final String PEM_STRING_X509_REQ_OLD="NEW CERTIFICATE REQUEST";
  132. public static final String PEM_STRING_X509_REQ="CERTIFICATE REQUEST";
  133. public static final String PEM_STRING_X509_CRL="X509 CRL";
  134. public static final String PEM_STRING_EVP_PKEY="ANY PRIVATE KEY";
  135. public static final String PEM_STRING_PUBLIC="PUBLIC KEY";
  136. public static final String PEM_STRING_RSA="RSA PRIVATE KEY";
  137. public static final String PEM_STRING_RSA_PUBLIC="RSA PUBLIC KEY";
  138. public static final String PEM_STRING_DSA="DSA PRIVATE KEY";
  139. public static final String PEM_STRING_DSA_PUBLIC="DSA PUBLIC KEY";
  140. public static final String PEM_STRING_PKCS7="PKCS7";
  141. public static final String PEM_STRING_PKCS8="ENCRYPTED PRIVATE KEY";
  142. public static final String PEM_STRING_PKCS8INF="PRIVATE KEY";
  143. public static final String PEM_STRING_DHPARAMS="DH PARAMETERS";
  144. public static final String PEM_STRING_SSL_SESSION="SSL SESSION PARAMETERS";
  145. public static final String PEM_STRING_DSAPARAMS="DSA PARAMETERS";
  146. public static final String PEM_STRING_ECDSA_PUBLIC="ECDSA PUBLIC KEY";
  147. public static final String PEM_STRING_ECPARAMETERS="EC PARAMETERS";
  148. public static final String PEM_STRING_ECPRIVATEKEY="EC PRIVATE KEY";
  149. private static final Pattern DH_PARAM_PATTERN = Pattern.compile(
  150. "(-----BEGIN DH PARAMETERS-----)(.*)(-----END DH PARAMETERS-----)",
  151. Pattern.MULTILINE);
  152. private static final int DH_PARAM_GROUP = 2; // the group above containing encoded params
  153. private static BufferedReader makeBuffered(Reader in) {
  154. if(in instanceof BufferedReader) {
  155. return (BufferedReader)in;
  156. }
  157. return new BufferedReader(in);
  158. }
  159. private static BufferedWriter makeBuffered(Writer out) {
  160. if(out instanceof BufferedWriter) {
  161. return (BufferedWriter)out;
  162. }
  163. return new BufferedWriter(out);
  164. }
  165. /**
  166. * c: PEM_X509_INFO_read_bio
  167. */
  168. public static Object readPEM(Reader in,char[] f) throws IOException {
  169. BufferedReader _in = makeBuffered(in);
  170. String line;
  171. while ((line = _in.readLine()) != null) {
  172. if(line.indexOf(BEF_G+PEM_STRING_PUBLIC) != -1) {
  173. try {
  174. return readPublicKey(_in,BEF_E+PEM_STRING_PUBLIC);
  175. } catch (Exception e) {
  176. throw new IOException("problem creating public key: " + e.toString());
  177. }
  178. } else if(line.indexOf(BEF_G+PEM_STRING_DSA) != -1) {
  179. try {
  180. return readKeyPair(_in,f, "DSA", BEF_E+PEM_STRING_DSA);
  181. } catch (Exception e) {
  182. throw new IOException("problem creating DSA private key: " + e.toString());
  183. }
  184. } else if(line.indexOf(BEF_G+PEM_STRING_RSA_PUBLIC) != -1) {
  185. try {
  186. return readPublicKey(_in,BEF_E+PEM_STRING_RSA_PUBLIC);
  187. } catch (Exception e) {
  188. throw new IOException("problem creating RSA public key: " + e.toString());
  189. }
  190. } else if(line.indexOf(BEF_G+PEM_STRING_X509_OLD) != -1) {
  191. try {
  192. return readAuxCertificate(_in,BEF_E+PEM_STRING_X509_OLD);
  193. } catch (Exception e) {
  194. throw new IOException("problem creating X509 Aux certificate: " + e.toString());
  195. }
  196. } else if(line.indexOf(BEF_G+PEM_STRING_X509) != -1) {
  197. try {
  198. return readAuxCertificate(_in,BEF_E+PEM_STRING_X509);
  199. } catch (Exception e) {
  200. throw new IOException("problem creating X509 Aux certificate: " + e.toString());
  201. }
  202. } else if(line.indexOf(BEF_G+PEM_STRING_X509_TRUSTED) != -1) {
  203. try {
  204. return readAuxCertificate(_in,BEF_E+PEM_STRING_X509_TRUSTED);
  205. } catch (Exception e) {
  206. throw new IOException("problem creating X509 Aux certificate: " + e.toString());
  207. }
  208. } else if(line.indexOf(BEF_G+PEM_STRING_X509_CRL) != -1) {
  209. try {
  210. return readCRL(_in,BEF_E+PEM_STRING_X509_CRL);
  211. } catch (Exception e) {
  212. throw new IOException("problem creating X509 CRL: " + e.toString());
  213. }
  214. } else if(line.indexOf(BEF_G+PEM_STRING_X509_REQ) != -1) {
  215. try {
  216. return readCertificateRequest(_in,BEF_E+PEM_STRING_X509_REQ);
  217. } catch (Exception e) {
  218. throw new IOException("problem creating X509 REQ: " + e.toString());
  219. }
  220. }
  221. }
  222. return null;
  223. }
  224. public static byte[] readX509PEM(Reader in) throws IOException {
  225. BufferedReader _in = makeBuffered(in);
  226. String line;
  227. while ((line = _in.readLine()) != null) {
  228. if (line.indexOf(BEF_G + PEM_STRING_X509_OLD) != -1) {
  229. try {
  230. return readBytes(_in, BEF_E + PEM_STRING_X509_OLD);
  231. } catch (Exception e) {
  232. throw new IOException("problem reading PEM X509 Aux certificate: " + e.toString());
  233. }
  234. } else if (line.indexOf(BEF_G + PEM_STRING_X509) != -1) {
  235. try {
  236. return readBytes(_in, BEF_E + PEM_STRING_X509);
  237. } catch (Exception e) {
  238. throw new IOException("problem reading PEM X509 Aux certificate: " + e.toString());
  239. }
  240. } else if (line.indexOf(BEF_G + PEM_STRING_X509_TRUSTED) != -1) {
  241. try {
  242. return readBytes(_in, BEF_E + PEM_STRING_X509_TRUSTED);
  243. } catch (Exception e) {
  244. throw new IOException("problem reading PEM X509 Aux certificate: " + e.toString());
  245. }
  246. } else if (line.indexOf(BEF_G + PEM_STRING_X509_CRL) != -1) {
  247. try {
  248. return readBytes(_in, BEF_E + PEM_STRING_X509_CRL);
  249. } catch (Exception e) {
  250. throw new IOException("problem reading PEM X509 CRL: " + e.toString());
  251. }
  252. } else if (line.indexOf(BEF_G + PEM_STRING_X509_REQ) != -1) {
  253. try {
  254. return readBytes(_in, BEF_E + PEM_STRING_X509_REQ);
  255. } catch (Exception e) {
  256. throw new IOException("problem reading PEM X509 REQ: " + e.toString());
  257. }
  258. }
  259. }
  260. return null;
  261. }
  262. /**
  263. * c: PEM_read_PrivateKey + PEM_read_bio_PrivateKey
  264. * CAUTION: KeyPair#getPublic() may be null.
  265. */
  266. public static KeyPair readPrivateKey(Reader in, char[] password) throws IOException {
  267. BufferedReader _in = makeBuffered(in);
  268. String line;
  269. while ((line = _in.readLine()) != null) {
  270. if (line.indexOf(BEF_G + PEM_STRING_RSA) != -1) {
  271. try {
  272. return readKeyPair(_in, password, "RSA", BEF_E + PEM_STRING_RSA);
  273. } catch (Exception e) {
  274. throw new IOException("problem creating RSA private key: " + e.toString());
  275. }
  276. } else if (line.indexOf(BEF_G + PEM_STRING_DSA) != -1) {
  277. try {
  278. return readKeyPair(_in, password, "DSA", BEF_E + PEM_STRING_DSA);
  279. } catch (Exception e) {
  280. throw new IOException("problem creating DSA private key: " + e.toString());
  281. }
  282. } else if (line.indexOf(BEF_G + PEM_STRING_ECPRIVATEKEY) != -1) {
  283. throw new IOException("EC private key not supported");
  284. } else if (line.indexOf(BEF_G + PEM_STRING_PKCS8INF) != -1) {
  285. try {
  286. byte[] bytes = readBytes(_in, BEF_E + PEM_STRING_PKCS8INF);
  287. PrivateKeyInfo info = PrivateKeyInfo.getInstance(bytes);
  288. String type = getPrivateKeyTypeFromObjectId(info.getPrivateKeyAlgorithm().getAlgorithm());
  289. return org.jruby.ext.openssl.impl.PKey.readPrivateKey(((ASN1Object) info.parsePrivateKey()).getEncoded(ASN1Encoding.DER), type);
  290. } catch (Exception e) {
  291. throw new IOException("problem creating private key: " + e.toString());
  292. }
  293. } else if (line.indexOf(BEF_G + PEM_STRING_PKCS8) != -1) {
  294. try {
  295. byte[] bytes = readBytes(_in, BEF_E + PEM_STRING_PKCS8);
  296. EncryptedPrivateKeyInfo eIn = EncryptedPrivateKeyInfo.getInstance(bytes);
  297. AlgorithmIdentifier algId = eIn.getEncryptionAlgorithm();
  298. PrivateKey privKey;
  299. if (algId.getAlgorithm().toString().equals("1.2.840.113549.1.5.13")) { // PBES2
  300. privKey = derivePrivateKeyPBES2(eIn, algId, password);
  301. } else {
  302. privKey = derivePrivateKeyPBES1(eIn, algId, password);
  303. }
  304. return new KeyPair(null, privKey);
  305. } catch (Exception e) {
  306. throw new IOException("problem creating private key: " + e.toString());
  307. }
  308. }
  309. }
  310. return null;
  311. }
  312. private static PrivateKey derivePrivateKeyPBES1(EncryptedPrivateKeyInfo eIn, AlgorithmIdentifier algId, char[] password)
  313. throws GeneralSecurityException, IOException {
  314. // From BC's PEMReader
  315. PKCS12PBEParams pkcs12Params = PKCS12PBEParams.getInstance(algId.getParameters());
  316. PBEKeySpec pbeSpec = new PBEKeySpec(password);
  317. PBEParameterSpec pbeParams = new PBEParameterSpec(
  318. pkcs12Params.getIV(), pkcs12Params.getIterations().intValue()
  319. );
  320. //String algorithm = algId.getAlgorithm().getId();
  321. String algorithm = ASN1Registry.o2a(algId.getAlgorithm());
  322. algorithm = (algorithm.split("-"))[0];
  323. SecretKeyFactory secKeyFact = SecretKeyFactory.getInstance(algorithm);
  324. Cipher cipher = Cipher.getInstance(algorithm);
  325. cipher.init(Cipher.DECRYPT_MODE, secKeyFact.generateSecret(pbeSpec), pbeParams);
  326. PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(
  327. ASN1Primitive.fromByteArray(cipher.doFinal(eIn.getEncryptedData()))
  328. );
  329. PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pInfo.getEncoded());
  330. String keyFactAlg = ASN1Registry.o2a(pInfo.getPrivateKeyAlgorithm().getAlgorithm());
  331. // TODO: Can we just set it to RSA as in derivePrivateKeyPBES2?
  332. KeyFactory keyFact;
  333. if (keyFactAlg.startsWith("dsa")) {
  334. keyFact = KeyFactory.getInstance("DSA");
  335. } else {
  336. keyFact = KeyFactory.getInstance("RSA");
  337. }
  338. return keyFact.generatePrivate(keySpec);
  339. }
  340. private static PrivateKey derivePrivateKeyPBES2(EncryptedPrivateKeyInfo eIn, AlgorithmIdentifier algId, char[] password)
  341. throws GeneralSecurityException, InvalidCipherTextException {
  342. PBES2Parameters pbeParams = new PBES2Parameters((ASN1Sequence) algId.getParameters());
  343. CipherParameters cipherParams = extractPBES2CipherParams(password, pbeParams);
  344. EncryptionScheme scheme = pbeParams.getEncryptionScheme();
  345. BufferedBlockCipher cipher;
  346. if (scheme.getAlgorithm().equals(PKCSObjectIdentifiers.RC2_CBC)) {
  347. RC2CBCParameter rc2Params = RC2CBCParameter.getInstance((ASN1Sequence) scheme.getObject());
  348. byte[] iv = rc2Params.getIV();
  349. CipherParameters param = new ParametersWithIV(cipherParams, iv);
  350. cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new RC2Engine()));
  351. cipher.init(false, param);
  352. } else {
  353. byte[] iv = ((ASN1OctetString) scheme.getObject()).getOctets();
  354. CipherParameters param = new ParametersWithIV(cipherParams, iv);
  355. cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new DESedeEngine()));
  356. cipher.init(false, param);
  357. }
  358. byte[] data = eIn.getEncryptedData();
  359. byte[] out = new byte[cipher.getOutputSize(data.length)];
  360. int len = cipher.processBytes(data, 0, data.length, out, 0);
  361. len += cipher.doFinal(out, len);
  362. byte[] pkcs8 = new byte[len];
  363. System.arraycopy(out, 0, pkcs8, 0, len);
  364. KeyFactory fact = KeyFactory.getInstance("RSA"); // It seems to work for both RSA and DSA.
  365. return fact.generatePrivate(new PKCS8EncodedKeySpec(pkcs8));
  366. }
  367. private static CipherParameters extractPBES2CipherParams(char[] password, PBES2Parameters pbeParams) {
  368. PBKDF2Params pbkdfParams = PBKDF2Params.getInstance(pbeParams.getKeyDerivationFunc().getParameters());
  369. int keySize = 192;
  370. if (pbkdfParams.getKeyLength() != null) {
  371. keySize = pbkdfParams.getKeyLength().intValue() * 8;
  372. }
  373. int iterationCount = pbkdfParams.getIterationCount().intValue();
  374. byte[] salt = pbkdfParams.getSalt();
  375. PBEParametersGenerator generator = new PKCS5S2ParametersGenerator();
  376. generator.init(PBEParametersGenerator.PKCS5PasswordToBytes(password), salt, iterationCount);
  377. return generator.generateDerivedParameters(keySize);
  378. }
  379. // PEM_read_bio_PUBKEY
  380. public static PublicKey readPubKey(Reader in) throws IOException {
  381. PublicKey pubKey = readRSAPubKey(in);
  382. if (pubKey == null) {
  383. pubKey = readDSAPubKey(in);
  384. }
  385. return pubKey;
  386. }
  387. /*
  388. * c: PEM_read_bio_DSA_PUBKEY
  389. */
  390. public static DSAPublicKey readDSAPubKey(Reader in) throws IOException {
  391. BufferedReader _in = makeBuffered(in);
  392. String line;
  393. while ((line = _in.readLine()) != null) {
  394. if(line.indexOf(BEF_G+PEM_STRING_DSA_PUBLIC) != -1) {
  395. try {
  396. return (DSAPublicKey)readPublicKey(_in,"DSA",BEF_E+PEM_STRING_DSA_PUBLIC);
  397. } catch (Exception e) {
  398. throw new IOException("problem creating DSA public key: " + e.toString());
  399. }
  400. }
  401. }
  402. return null;
  403. }
  404. /*
  405. * c: PEM_read_bio_DSAPublicKey
  406. */
  407. public static DSAPublicKey readDSAPublicKey(Reader in, char[] f) throws IOException {
  408. BufferedReader _in = makeBuffered(in);
  409. String line;
  410. while ((line = _in.readLine()) != null) {
  411. if(line.indexOf(BEF_G+PEM_STRING_PUBLIC) != -1) {
  412. try {
  413. return (DSAPublicKey)readPublicKey(_in,"DSA",BEF_E+PEM_STRING_PUBLIC);
  414. } catch (Exception e) {
  415. throw new IOException("problem creating DSA public key: " + e.toString());
  416. }
  417. }
  418. }
  419. return null;
  420. }
  421. /*
  422. * c: PEM_read_bio_DSAPrivateKey
  423. */
  424. public static KeyPair readDSAPrivateKey(Reader in, char[] f) throws IOException {
  425. BufferedReader _in = makeBuffered(in);
  426. String line;
  427. while ((line = _in.readLine()) != null) {
  428. if(line.indexOf(BEF_G+PEM_STRING_DSA) != -1) {
  429. try {
  430. return readKeyPair(_in,f, "DSA", BEF_E+PEM_STRING_DSA);
  431. } catch (Exception e) {
  432. throw new IOException("problem creating DSA private key: " + e.toString());
  433. }
  434. }
  435. }
  436. return null;
  437. }
  438. /**
  439. * reads an RSA public key encoded in an SubjectPublicKeyInfo RSA structure.
  440. * c: PEM_read_bio_RSA_PUBKEY
  441. */
  442. public static RSAPublicKey readRSAPubKey(Reader in) throws IOException {
  443. BufferedReader _in = makeBuffered(in);
  444. String line;
  445. while ((line = _in.readLine()) != null) {
  446. if(line.indexOf(BEF_G+PEM_STRING_PUBLIC) != -1) {
  447. try {
  448. return readRSAPublicKey(_in,BEF_E+PEM_STRING_PUBLIC);
  449. } catch (Exception e) {
  450. throw new IOException("problem creating RSA public key: " + e.toString());
  451. }
  452. } else if(line.indexOf(BEF_G+PEM_STRING_RSA_PUBLIC) != -1) {
  453. try {
  454. return readRSAPublicKey(_in,BEF_E+PEM_STRING_RSA_PUBLIC);
  455. } catch (Exception e) {
  456. throw new IOException("problem creating RSA public key: " + e.toString());
  457. }
  458. }
  459. }
  460. return null;
  461. }
  462. /**
  463. * reads an RSA public key encoded in an PKCS#1 RSA structure.
  464. * c: PEM_read_bio_RSAPublicKey
  465. */
  466. public static RSAPublicKey readRSAPublicKey(Reader in, char[] f) throws IOException {
  467. BufferedReader _in = makeBuffered(in);
  468. String line;
  469. while ((line = _in.readLine()) != null) {
  470. if(line.indexOf(BEF_G+PEM_STRING_PUBLIC) != -1) {
  471. try {
  472. return (RSAPublicKey)readPublicKey(_in,"RSA",BEF_E+PEM_STRING_PUBLIC);
  473. } catch (Exception e) {
  474. throw new IOException("problem creating RSA public key: " + e.toString());
  475. }
  476. } else if(line.indexOf(BEF_G+PEM_STRING_RSA_PUBLIC) != -1) {
  477. try {
  478. return (RSAPublicKey)readPublicKey(_in,"RSA",BEF_E+PEM_STRING_RSA_PUBLIC);
  479. } catch (Exception e) {
  480. throw new IOException("problem creating RSA public key: " + e.toString());
  481. }
  482. }
  483. }
  484. return null;
  485. }
  486. /**
  487. * c: PEM_read_bio_RSAPrivateKey
  488. */
  489. public static KeyPair readRSAPrivateKey(Reader in, char[] f) throws IOException {
  490. BufferedReader _in = makeBuffered(in);
  491. String line;
  492. while ((line = _in.readLine()) != null) {
  493. if(line.indexOf(BEF_G+PEM_STRING_RSA) != -1) {
  494. try {
  495. return readKeyPair(_in,f, "RSA", BEF_E+PEM_STRING_RSA);
  496. } catch (Exception e) {
  497. throw new IOException("problem creating RSA private key: " + e.toString());
  498. }
  499. }
  500. }
  501. return null;
  502. }
  503. public static CMSSignedData readPKCS7(Reader in, char[] f) throws IOException {
  504. BufferedReader _in = makeBuffered(in);
  505. String line;
  506. while ((line = _in.readLine()) != null) {
  507. if(line.indexOf(BEF_G+PEM_STRING_PKCS7) != -1) {
  508. try {
  509. return readPKCS7(_in,f, BEF_E+PEM_STRING_PKCS7);
  510. } catch (Exception e) {
  511. throw new IOException("problem creating PKCS7: " + e.toString());
  512. }
  513. }
  514. }
  515. return null;
  516. }
  517. public static X509AuxCertificate readX509Certificate(Reader in, char[] f) throws IOException {
  518. BufferedReader _in = makeBuffered(in);
  519. String line;
  520. while ((line = _in.readLine()) != null) {
  521. if(line.indexOf(BEF_G+PEM_STRING_X509_OLD) != -1) {
  522. try {
  523. return new X509AuxCertificate(readCertificate(_in,BEF_E+PEM_STRING_X509_OLD));
  524. } catch (Exception e) {
  525. throw new IOException("problem creating X509 certificate: " + e.toString());
  526. }
  527. } else if(line.indexOf(BEF_G+PEM_STRING_X509) != -1) {
  528. try {
  529. return new X509AuxCertificate(readCertificate(_in,BEF_E+PEM_STRING_X509));
  530. } catch (Exception e) {
  531. throw new IOException("problem creating X509 certificate: " + e.toString());
  532. }
  533. } else if(line.indexOf(BEF_G+PEM_STRING_X509_TRUSTED) != -1) {
  534. try {
  535. return new X509AuxCertificate(readCertificate(_in,BEF_E+PEM_STRING_X509_TRUSTED));
  536. } catch (Exception e) {
  537. throw new IOException("problem creating X509 certificate: " + e.toString());
  538. }
  539. }
  540. }
  541. return null;
  542. }
  543. public static X509AuxCertificate readX509Aux(Reader in, char[] f) throws IOException {
  544. BufferedReader _in = makeBuffered(in);
  545. String line;
  546. while ((line = _in.readLine()) != null) {
  547. if(line.indexOf(BEF_G+PEM_STRING_X509_OLD) != -1) {
  548. try {
  549. return readAuxCertificate(_in,BEF_E+PEM_STRING_X509_OLD);
  550. } catch (Exception e) {
  551. throw new IOException("problem creating X509 Aux certificate: " + e.toString());
  552. }
  553. } else if(line.indexOf(BEF_G+PEM_STRING_X509) != -1) {
  554. try {
  555. return readAuxCertificate(_in,BEF_E+PEM_STRING_X509);
  556. } catch (Exception e) {
  557. throw new IOException("problem creating X509 Aux certificate: " + e.toString());
  558. }
  559. } else if(line.indexOf(BEF_G+PEM_STRING_X509_TRUSTED) != -1) {
  560. try {
  561. return readAuxCertificate(_in,BEF_E+PEM_STRING_X509_TRUSTED);
  562. } catch (Exception e) {
  563. throw new IOException("problem creating X509 Aux certificate: " + e.toString());
  564. }
  565. }
  566. }
  567. return null;
  568. }
  569. public static X509CRL readX509CRL(Reader in, char[] f) throws IOException {
  570. BufferedReader _in = makeBuffered(in);
  571. String line;
  572. while ((line = _in.readLine()) != null) {
  573. if(line.indexOf(BEF_G+PEM_STRING_X509_CRL) != -1) {
  574. try {
  575. return readCRL(_in,BEF_E+PEM_STRING_X509_CRL);
  576. } catch (Exception e) {
  577. throw new IOException("problem creating X509 CRL: " + e.toString());
  578. }
  579. }
  580. }
  581. return null;
  582. }
  583. public static PKCS10Request readX509Request(Reader in, char[] f) throws IOException {
  584. BufferedReader _in = makeBuffered(in);
  585. String line;
  586. while ((line = _in.readLine()) != null) {
  587. if(line.indexOf(BEF_G+PEM_STRING_X509_REQ) != -1) {
  588. try {
  589. return readCertificateRequest(_in,BEF_E+PEM_STRING_X509_REQ);
  590. } catch (Exception e) {
  591. throw new IOException("problem creating X509 REQ: " + e.toString());
  592. }
  593. }
  594. }
  595. return null;
  596. }
  597. public static DHParameterSpec readDHParameters(Reader _in) throws IOException {
  598. BufferedReader in = makeBuffered(_in);
  599. String line;
  600. StringBuilder buf = new StringBuilder();
  601. while ((line = in.readLine()) != null) {
  602. if (line.indexOf(BEF_G + PEM_STRING_DHPARAMS) >= 0) {
  603. do {
  604. buf.append(line.trim());
  605. } while (line.indexOf(BEF_E + PEM_STRING_DHPARAMS) < 0 && (line = in.readLine()) != null);
  606. break;
  607. }
  608. }
  609. Matcher m = DH_PARAM_PATTERN.matcher(buf.toString());
  610. if (m.find()) {
  611. try {
  612. byte[] decoded = Base64.decode(m.group(DH_PARAM_GROUP));
  613. return org.jruby.ext.openssl.impl.PKey.readDHParameter(decoded);
  614. } catch (Exception e) {
  615. }
  616. }
  617. return null;
  618. }
  619. private static byte[] getEncoded(java.security.Key key) {
  620. if (key != null) {
  621. return key.getEncoded();
  622. }
  623. return new byte[] { '0', 0 };
  624. }
  625. private static byte[] getEncoded(ASN1Encodable obj) throws IOException {
  626. if (obj != null) {
  627. return obj.toASN1Primitive().getEncoded();
  628. }
  629. return new byte[] { '0', 0 };
  630. }
  631. private static byte[] getEncoded(CMSSignedData obj) throws IOException {
  632. if (obj != null) {
  633. return obj.getEncoded();
  634. }
  635. return new byte[] { '0', 0 };
  636. }
  637. private static byte[] getEncoded(X509Certificate cert) throws IOException {
  638. if (cert != null) {
  639. try {
  640. return cert.getEncoded();
  641. } catch (GeneralSecurityException gse) {
  642. throw new IOException("problem with encoding object in write_X509");
  643. }
  644. }
  645. return new byte[] { '0', 0 };
  646. }
  647. private static byte[] getEncoded(X509CRL crl) throws IOException {
  648. if (crl != null) {
  649. try {
  650. return crl.getEncoded();
  651. } catch (GeneralSecurityException gse) {
  652. throw new IOException("problem with encoding object in write_X509_CRL");
  653. }
  654. }
  655. return new byte[] { '0', 0 };
  656. }
  657. public static void writeDSAPublicKey(Writer _out, DSAPublicKey obj) throws IOException {
  658. BufferedWriter out = makeBuffered(_out);
  659. byte[] encoding = getEncoded(obj);
  660. out.write(BEF_G + PEM_STRING_DSA_PUBLIC + AFT);
  661. out.newLine();
  662. writeEncoded(out, encoding);
  663. out.write(BEF_E + PEM_STRING_DSA_PUBLIC + AFT);
  664. out.newLine();
  665. out.flush();
  666. }
  667. /** writes an RSA public key encoded in an PKCS#1 RSA structure. */
  668. public static void writeRSAPublicKey(Writer _out, RSAPublicKey obj) throws IOException {
  669. BufferedWriter out = makeBuffered(_out);
  670. byte[] encoding = getEncoded(obj);
  671. out.write(BEF_G + PEM_STRING_RSA_PUBLIC + AFT);
  672. out.newLine();
  673. writeEncoded(out, encoding);
  674. out.write(BEF_E + PEM_STRING_RSA_PUBLIC + AFT);
  675. out.newLine();
  676. out.flush();
  677. }
  678. public static void writePKCS7(Writer _out, ContentInfo obj) throws IOException {
  679. BufferedWriter out = makeBuffered(_out);
  680. byte[] encoding = getEncoded(obj);
  681. out.write(BEF_G + PEM_STRING_PKCS7 + AFT);
  682. out.newLine();
  683. writeEncoded(out,encoding);
  684. out.write(BEF_E + PEM_STRING_PKCS7 + AFT);
  685. out.newLine();
  686. out.flush();
  687. }
  688. public static void writePKCS7(Writer _out, CMSSignedData obj) throws IOException {
  689. BufferedWriter out = makeBuffered(_out);
  690. byte[] encoding = getEncoded(obj);
  691. out.write(BEF_G + PEM_STRING_PKCS7 + AFT);
  692. out.newLine();
  693. writeEncoded(out,encoding);
  694. out.write(BEF_E + PEM_STRING_PKCS7 + AFT);
  695. out.newLine();
  696. out.flush();
  697. }
  698. public static void writePKCS7(Writer _out, byte[] encoded) throws IOException {
  699. BufferedWriter out = makeBuffered(_out);
  700. out.write(BEF_G + PEM_STRING_PKCS7 + AFT);
  701. out.newLine();
  702. writeEncoded(out,encoded);
  703. out.write(BEF_E + PEM_STRING_PKCS7 + AFT);
  704. out.newLine();
  705. out.flush();
  706. }
  707. public static void writeX509Certificate(Writer _out, X509Certificate obj) throws IOException {
  708. BufferedWriter out = makeBuffered(_out);
  709. byte[] encoding = getEncoded(obj);
  710. out.write(BEF_G + PEM_STRING_X509 + AFT);
  711. out.newLine();
  712. writeEncoded(out, encoding);
  713. out.write(BEF_E + PEM_STRING_X509 + AFT);
  714. out.newLine();
  715. out.flush();
  716. }
  717. public static void writeX509Aux(Writer _out, X509AuxCertificate obj) throws IOException {
  718. BufferedWriter out = makeBuffered(_out);
  719. byte[] encoding = null;
  720. try {
  721. if(obj.getAux() == null) {
  722. encoding = obj.getEncoded();
  723. } else {
  724. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  725. byte[] ymp = obj.getEncoded();
  726. baos.write(ymp,0,ymp.length);
  727. X509Aux aux = obj.getAux();
  728. ASN1EncodableVector a1 = new ASN1EncodableVector();
  729. if(aux.trust.size()>0) {
  730. ASN1EncodableVector a2 = new ASN1EncodableVector();
  731. for(String trust : aux.trust) {
  732. a2.add(new ASN1ObjectIdentifier(trust));
  733. }
  734. a1.add(new DLSequence(a2));
  735. }
  736. if(aux.reject.size()>0) {
  737. ASN1EncodableVector a2 = new ASN1EncodableVector();
  738. for(String reject : aux.reject) {
  739. a2.add(new ASN1ObjectIdentifier(reject));
  740. }
  741. a1.add(new DERTaggedObject(0,new DLSequence(a2)));
  742. }
  743. if(aux.alias != null) {
  744. a1.add(new DERUTF8String(aux.alias));
  745. }
  746. if(aux.keyid != null) {
  747. a1.add(new DEROctetString(aux.keyid));
  748. }
  749. if(aux.other.size()>0) {
  750. ASN1EncodableVector a2 = new ASN1EncodableVector();
  751. for(ASN1Primitive other : aux.other) {
  752. a2.add(other);
  753. }
  754. a1.add(new DERTaggedObject(1,new DLSequence(a2)));
  755. }
  756. ymp = new DLSequence(a1).getEncoded();
  757. baos.write(ymp,0,ymp.length);
  758. encoding = baos.toByteArray();
  759. }
  760. } catch(CertificateEncodingException e) {
  761. throw new IOException("problem with encoding object in write_X509_AUX");
  762. }
  763. out.write(BEF_G + PEM_STRING_X509_TRUSTED + AFT);
  764. out.newLine();
  765. writeEncoded(out,encoding);
  766. out.write(BEF_E + PEM_STRING_X509_TRUSTED + AFT);
  767. out.newLine();
  768. out.flush();
  769. }
  770. public static void writeX509CRL(Writer _out, X509CRL obj) throws IOException {
  771. BufferedWriter out = makeBuffered(_out);
  772. byte[] encoding = getEncoded(obj);
  773. out.write(BEF_G + PEM_STRING_X509_CRL + AFT);
  774. out.newLine();
  775. writeEncoded(out, encoding);
  776. out.write(BEF_E + PEM_STRING_X509_CRL + AFT);
  777. out.newLine();
  778. out.flush();
  779. }
  780. public static void writeX509Request(Writer _out, PKCS10Request obj) throws IOException {
  781. BufferedWriter out = makeBuffered(_out);
  782. byte[] encoding = getEncoded(obj.toASN1Structure());
  783. out.write(BEF_G + PEM_STRING_X509_REQ + AFT);
  784. out.newLine();
  785. writeEncoded(out,encoding);
  786. out.write(BEF_E + PEM_STRING_X509_REQ + AFT);
  787. out.newLine();
  788. out.flush();
  789. }
  790. private static SecureRandom random;
  791. static {
  792. try {
  793. random = SecureRandom.getInstance("SHA1PRNG");
  794. } catch(Exception e) {
  795. random = null;
  796. }
  797. }
  798. public static void writeDSAPrivateKey(Writer _out, DSAPrivateKey obj, CipherSpec cipher, char[] passwd) throws IOException {
  799. BufferedWriter out = makeBuffered(_out);
  800. PrivateKeyInfo info = new PrivateKeyInfo((ASN1Sequence) new ASN1InputStream(getEncoded(obj)).readObject());
  801. ByteArrayOutputStream bOut = new ByteArrayOutputStream();
  802. ASN1OutputStream aOut = new ASN1OutputStream(bOut);
  803. DSAParameter p = DSAParameter.getInstance(info.getPrivateKeyAlgorithm().getParameters());
  804. ASN1EncodableVector v = new ASN1EncodableVector();
  805. v.add(new ASN1Integer(0));
  806. v.add(new ASN1Integer(p.getP()));
  807. v.add(new ASN1Integer(p.getQ()));
  808. v.add(new ASN1Integer(p.getG()));
  809. BigInteger x = obj.getX();
  810. BigInteger y = p.getG().modPow(x, p.getP());
  811. v.add(new ASN1Integer(y));
  812. v.add(new ASN1Integer(x));
  813. aOut.writeObject(new DLSequence(v));
  814. byte[] encoding = bOut.toByteArray();
  815. if (cipher != null && passwd != null) {
  816. writePemEncrypted(out, PEM_STRING_DSA, encoding, cipher, passwd);
  817. } else {
  818. writePemPlain(out, PEM_STRING_DSA, encoding);
  819. }
  820. }
  821. public static void writeRSAPrivateKey(Writer _out, RSAPrivateCrtKey obj, CipherSpec cipher, char[] passwd) throws IOException {
  822. assert (obj != null);
  823. BufferedWriter out = makeBuffered(_out);
  824. org.bouncycastle.asn1.pkcs.RSAPrivateKey keyStruct = new org.bouncycastle.asn1.pkcs.RSAPrivateKey(obj.getModulus(), obj.getPublicExponent(), obj.getPrivateExponent(), obj.getPrimeP(),
  825. obj.getPrimeQ(), obj.getPrimeExponentP(), obj.getPrimeExponentQ(), obj.getCrtCoefficient());
  826. if (cipher != null && passwd != null) {
  827. writePemEncrypted(out, PEM_STRING_RSA, keyStruct.getEncoded(), cipher, passwd);
  828. } else {
  829. writePemPlain(out, PEM_STRING_RSA, keyStruct.getEncoded());
  830. }
  831. }
  832. private static void writePemPlain(BufferedWriter out, String pemHeader, byte[] encoding) throws IOException {
  833. out.write(BEF_G + pemHeader + AFT);
  834. out.newLine();
  835. writeEncoded(out, encoding);
  836. out.write(BEF_E + pemHeader + AFT);
  837. out.newLine();
  838. out.flush();
  839. }
  840. private static void writePemEncrypted(BufferedWriter out, String pemHeader, byte[] encoding, CipherSpec cipher, char[] passwd) throws IOException {
  841. Cipher c = cipher.getCipher();
  842. byte[] iv = new byte[c.getBlockSize()];
  843. random.nextBytes(iv);
  844. byte[] salt = new byte[8];
  845. System.arraycopy(iv, 0, salt, 0, 8);
  846. OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator();
  847. pGen.init(PBEParametersGenerator.PKCS5PasswordToBytes(passwd), salt);
  848. KeyParameter param = (KeyParameter) pGen.generateDerivedParameters(cipher.getKeyLenInBits());
  849. SecretKey secretKey = new SecretKeySpec(param.getKey(), org.jruby.ext.openssl.Cipher.Algorithm.getAlgorithmBase(c));
  850. byte[] encData = null;
  851. try {
  852. c.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
  853. encData = c.doFinal(encoding);
  854. } catch (GeneralSecurityException gse) {
  855. throw new IOException("exception using cipher: " + gse.toString());
  856. }
  857. out.write(BEF_G + pemHeader + AFT);
  858. out.newLine();
  859. out.write("Proc-Type: 4,ENCRYPTED");
  860. out.newLine();
  861. out.write("DEK-Info: " + cipher.getOsslName() + ",");
  862. writeHexEncoded(out, iv);
  863. out.newLine();
  864. out.newLine();
  865. writeEncoded(out, encData);
  866. out.write(BEF_E + pemHeader + AFT);
  867. out.flush();
  868. }
  869. public static void writeDHParameters(Writer _out, DHParameterSpec params) throws IOException {
  870. BufferedWriter out = makeBuffered(_out);
  871. ByteArrayOutputStream bOut = new ByteArrayOutputStream();
  872. ASN1OutputStream aOut = new ASN1OutputStream(bOut);
  873. ASN1EncodableVector v = new ASN1EncodableVector();
  874. BigInteger value;
  875. if ((value = params.getP()) != null) {
  876. v.add(new ASN1Integer(value));
  877. }
  878. if ((value = params.getG()) != null) {
  879. v.add(new ASN1Integer(value));
  880. }
  881. aOut.writeObject(new DLSequence(v));
  882. byte[] encoding = bOut.toByteArray();
  883. out.write(BEF_G + PEM_STRING_DHPARAMS + AFT);
  884. out.newLine();
  885. writeEncoded(out,encoding);
  886. out.write(BEF_E + PEM_STRING_DHPARAMS + AFT);
  887. out.newLine();
  888. out.flush();
  889. }
  890. private static String getPrivateKeyTypeFromObjectId(ASN1ObjectIdentifier oid) {
  891. if (ASN1Registry.obj2nid(oid) == ASN1Registry.NID_rsaEncryption) {
  892. return "RSA";
  893. } else {
  894. return "DSA";
  895. }
  896. }
  897. private static byte[] readBytes(BufferedReader in, String endMarker) throws IOException {
  898. String line;
  899. StringBuffer buf = new StringBuffer();
  900. while ((line = in.readLine()) != null) {
  901. if (line.indexOf(endMarker) != -1) {
  902. break;
  903. }
  904. buf.append(line.trim());
  905. }
  906. if (line == null) {
  907. throw new IOException(endMarker + " not found");
  908. }
  909. return Base64.decode(buf.toString());
  910. }
  911. private static RSAPublicKey readRSAPublicKey(BufferedReader in, String endMarker) throws IOException {
  912. Object asnObject = new ASN1InputStream(readBytes(in, endMarker)).readObject();
  913. ASN1Sequence sequence = (ASN1Sequence) asnObject;
  914. org.bouncycastle.asn1.pkcs.RSAPublicKey rsaPubStructure = org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(sequence);
  915. RSAPublicKeySpec keySpec = new RSAPublicKeySpec(
  916. rsaPubStructure.getModulus(),
  917. rsaPubStructure.getPublicExponent());
  918. try {
  919. KeyFactory keyFact = KeyFactory.getInstance("RSA");
  920. return (RSAPublicKey) keyFact.generatePublic(keySpec);
  921. } catch (NoSuchAlgorithmException e) {
  922. // ignore
  923. } catch (InvalidKeySpecException e) {
  924. // ignore
  925. }
  926. return null;
  927. }
  928. private static PublicKey readPublicKey(byte[] input, String alg, String endMarker) throws IOException {
  929. KeySpec keySpec = new X509EncodedKeySpec(input);
  930. try {
  931. KeyFactory keyFact = KeyFactory.getInstance(alg);
  932. PublicKey pubKey = keyFact.generatePublic(keySpec);
  933. return pubKey;
  934. } catch (NoSuchAlgorithmException e) {
  935. // ignore
  936. } catch (InvalidKeySpecException e) {
  937. // ignore
  938. }
  939. return null;
  940. }
  941. private static PublicKey readPublicKey(BufferedReader in, String alg, String endMarker) throws IOException {
  942. return readPublicKey(readBytes(in, endMarker), alg, endMarker);
  943. }
  944. private static PublicKey readPublicKey(BufferedReader in, String endMarker) throws IOException {
  945. byte[] input = readBytes(in, endMarker);
  946. String[] algs = { "RSA", "DSA" };
  947. for (int i = 0; i < algs.length; i++) {
  948. PublicKey key = readPublicKey(input, algs[i], endMarker);
  949. if (key != null) {
  950. return key;
  951. }
  952. }
  953. return null;
  954. }
  955. /**
  956. * Read a Key Pair
  957. */
  958. private static KeyPair readKeyPair(BufferedReader _in, char[] passwd, String type, String endMarker) throws Exception {
  959. boolean isEncrypted = false;
  960. String line = null;
  961. String dekInfo = null;
  962. StringBuilder buf = new StringBuilder();
  963. while ((line = _in.readLine()) != null) {
  964. if (line.startsWith("Proc-Type: 4,ENCRYPTED")) {
  965. isEncrypted = true;
  966. } else if (line.startsWith("DEK-Info:")) {
  967. dekInfo = line.substring(10);
  968. } else if (line.indexOf(endMarker) != -1) {
  969. break;
  970. } else {
  971. buf.append(line.trim());
  972. }
  973. }
  974. byte[] keyBytes = null;
  975. byte[] decoded = Base64.decode(buf.toString());
  976. if (isEncrypted) {
  977. keyBytes = decrypt(decoded, dekInfo, passwd);
  978. } else {
  979. keyBytes = decoded;
  980. }
  981. return org.jruby.ext.openssl.impl.PKey.readPrivateKey(keyBytes, type);
  982. }
  983. private static byte[] decrypt(byte[] decoded, String dekInfo, char[] passwd) throws IOException, GeneralSecurityException {
  984. if (passwd == null) {
  985. throw new IOException("Password is null, but a password is required");
  986. }
  987. StringTokenizer tknz = new StringTokenizer(dekInfo, ",");
  988. String algorithm = tknz.nextToken();
  989. byte[] iv = Hex.decode(tknz.nextToken());
  990. if (!CipherModule.isSupportedCipher(algorithm)) {
  991. throw new IOException("Unknown algorithm: " + algorithm);
  992. }
  993. String[] cipher = org.jruby.ext.openssl.Cipher.Algorithm.osslToJsse(algorithm);
  994. String realName = cipher[3];
  995. int[] lengths = org.jruby.ext.openssl.Cipher.Algorithm.osslKeyIvLength(algorithm);
  996. int keyLen = lengths[0];
  997. int ivLen = lengths[1];
  998. if (iv.length != ivLen) {
  999. throw new IOException("Illegal IV length");
  1000. }
  1001. byte[] salt = new byte[8];
  1002. System.arraycopy(iv, 0, salt, 0, 8);
  1003. OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator();
  1004. pGen.init(PBEParametersGenerator.PKCS5PasswordToBytes(passwd), salt);
  1005. KeyParameter param = (KeyParameter) pGen.generateDerivedParameters(keyLen * 8);
  1006. SecretKey secretKey = new javax.crypto.spec.SecretKeySpec(param.getKey(), realName);
  1007. Cipher c = Cipher.getInstance(realName);
  1008. c.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
  1009. return c.doFinal(decoded);
  1010. }
  1011. /**
  1012. * Reads in a X509Certificate.
  1013. *
  1014. * @return the X509Certificate
  1015. * @throws IOException if an I/O error occured
  1016. */
  1017. private static X509Certificate readCertificate(BufferedReader in, String endMarker) throws IOException {
  1018. String line;
  1019. StringBuilder buf = new StringBuilder();
  1020. while ((line = in.readLine()) != null) {
  1021. if (line.indexOf(endMarker) != -1) {
  1022. break;
  1023. }
  1024. buf.append(line.trim());
  1025. }
  1026. if (line == null) {
  1027. throw new IOException(endMarker + " not found");
  1028. }
  1029. try {
  1030. CertificateFactory certFact = CertificateFactory.getInstance("X.509");
  1031. ByteArrayInputStream bIn = new ByteArrayInputStream(Base64.decode(buf.toString()));
  1032. return (X509Certificate) certFact.generateCertificate(bIn);
  1033. } catch (Exception e) {
  1034. throw new IOException("problem parsing cert: " + e.toString());
  1035. }
  1036. }
  1037. private static X509AuxCertificate readAuxCertificate(BufferedReader in,String endMarker) throws IOException {
  1038. String line;
  1039. StringBuilder buf = new StringBuilder();
  1040. while ((line = in.readLine()) != null) {
  1041. if (line.indexOf(endMarker) != -1) {
  1042. break;
  1043. }
  1044. buf.append(line.trim());
  1045. }
  1046. if (line == null) {
  1047. throw new IOException(endMarker + " not found");
  1048. }
  1049. ASN1InputStream try1 = new ASN1InputStream(Base64.decode(buf.toString()));
  1050. ByteArrayInputStream bIn = new ByteArrayInputStream((try1.readObject()).getEncoded());
  1051. try {
  1052. CertificateFactory certFact = CertificateFactory.getInstance("X.509");
  1053. X509Certificate bCert = (X509Certificate)certFact.generateCertificate(bIn);
  1054. ASN1Sequence aux = (ASN1Sequence)try1.readObject();
  1055. X509Aux ax = null;
  1056. if(aux != null) {
  1057. ax = new X509Aux();
  1058. int ix = 0;
  1059. if(aux.size() > ix && aux.getObjectAt(ix) instanceof ASN1Sequence) {
  1060. ASN1Sequence trust = (ASN1Sequence)aux.getObjectAt(ix++);
  1061. for(int i=0;i<trust.size();i++) {
  1062. ax.trust.add(((ASN1ObjectIdentifier)trust.getObjectAt(i)).getId());
  1063. }
  1064. }
  1065. if(aux.size() > ix && aux.getObjectAt(ix) instanceof ASN1TaggedObject && ((ASN1TaggedObject)aux.getObjectAt(ix)).getTagNo() == 0) {
  1066. ASN1Sequence reject = (ASN1Sequence)((ASN1TaggedObject)aux.getObjectAt(ix++)).getObject();
  1067. for(int i=0;i<reject.size();i++) {
  1068. ax.reject.add(((ASN1ObjectIdentifier)reject.getObjectAt(i)).getId());
  1069. }
  1070. }
  1071. if(aux.size()>ix && aux.getObjectAt(ix) instanceof DERUTF8String) {
  1072. ax.alias = ((DERUTF8String)aux.getObjectAt(ix++)).getString();
  1073. }
  1074. if(aux.size()>ix && aux.getObjectAt(ix) instanceof DEROctetString) {
  1075. ax.keyid = ((DEROctetString)aux.getObjectAt(ix++)).getOctets();
  1076. }
  1077. if(aux.size() > ix && aux.getObjectAt(ix) instanceof ASN1TaggedObject && ((ASN1TaggedObject)aux.getObjectAt(ix)).getTagNo() == 1) {
  1078. ASN1Sequence other = (ASN1Sequence)((ASN1TaggedObject)aux.getObjectAt(ix++)).getObject();
  1079. for(int i=0;i<other.size();i++) {