1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.ssl;
17
18 import io.netty.handler.ssl.util.BouncyCastleUtil;
19 import io.netty.util.CharsetUtil;
20 import io.netty.util.internal.logging.InternalLogger;
21 import io.netty.util.internal.logging.InternalLoggerFactory;
22 import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
23 import org.bouncycastle.openssl.PEMDecryptorProvider;
24 import org.bouncycastle.openssl.PEMEncryptedKeyPair;
25 import org.bouncycastle.openssl.PEMKeyPair;
26 import org.bouncycastle.openssl.PEMParser;
27 import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
28 import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
29 import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
30 import org.bouncycastle.operator.InputDecryptorProvider;
31 import org.bouncycastle.operator.OperatorCreationException;
32 import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
33 import org.bouncycastle.pkcs.PKCSException;
34
35 import java.io.File;
36 import java.io.FileNotFoundException;
37 import java.io.FileReader;
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.io.InputStreamReader;
41 import java.security.PrivateKey;
42
43 final class BouncyCastlePemReader {
44 private static final InternalLogger logger = InternalLoggerFactory.getInstance(BouncyCastlePemReader.class);
45
46
47
48
49
50
51
52
53
54 public static PrivateKey getPrivateKey(InputStream keyInputStream, String keyPassword) {
55 if (!BouncyCastleUtil.isBcPkixAvailable()) {
56 if (logger.isDebugEnabled()) {
57 logger.debug("Bouncy castle provider is unavailable.", BouncyCastleUtil.unavailabilityCauseBcPkix());
58 }
59 return null;
60 }
61 try {
62 PEMParser parser = newParser(keyInputStream);
63 return getPrivateKey(parser, keyPassword);
64 } catch (Exception e) {
65 logger.debug("Unable to extract private key", e);
66 return null;
67 }
68 }
69
70
71
72
73
74
75
76
77
78 public static PrivateKey getPrivateKey(File keyFile, String keyPassword) {
79 if (!BouncyCastleUtil.isBcPkixAvailable()) {
80 if (logger.isDebugEnabled()) {
81 logger.debug("Bouncy castle provider is unavailable.", BouncyCastleUtil.unavailabilityCauseBcPkix());
82 }
83 return null;
84 }
85 try {
86 PEMParser parser = newParser(keyFile);
87 return getPrivateKey(parser, keyPassword);
88 } catch (Exception e) {
89 logger.debug("Unable to extract private key", e);
90 return null;
91 }
92 }
93
94 private static JcaPEMKeyConverter newConverter() {
95 return new JcaPEMKeyConverter().setProvider(BouncyCastleUtil.getBcProviderJce());
96 }
97
98 private static PrivateKey getPrivateKey(PEMParser pemParser, String keyPassword) throws IOException,
99 PKCSException, OperatorCreationException {
100 try {
101 JcaPEMKeyConverter converter = newConverter();
102 PrivateKey pk = null;
103
104 Object object = pemParser.readObject();
105 while (object != null && pk == null) {
106 if (logger.isDebugEnabled()) {
107 logger.debug("Parsed PEM object of type {} and assume " +
108 "key is {}encrypted", object.getClass().getName(), keyPassword == null? "not " : "");
109 }
110
111 if (keyPassword == null) {
112
113 if (object instanceof PrivateKeyInfo) {
114 pk = converter.getPrivateKey((PrivateKeyInfo) object);
115 } else if (object instanceof PEMKeyPair) {
116 pk = converter.getKeyPair((PEMKeyPair) object).getPrivate();
117 } else {
118 logger.debug("Unable to handle PEM object of type {} as a non encrypted key",
119 object.getClass());
120 }
121 } else {
122
123 if (object instanceof PEMEncryptedKeyPair) {
124 PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder()
125 .setProvider(BouncyCastleUtil.getBcProviderJce())
126 .build(keyPassword.toCharArray());
127 pk = converter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv)).getPrivate();
128 } else if (object instanceof PKCS8EncryptedPrivateKeyInfo) {
129 InputDecryptorProvider pkcs8InputDecryptorProvider =
130 new JceOpenSSLPKCS8DecryptorProviderBuilder()
131 .setProvider(BouncyCastleUtil.getBcProviderJce())
132 .build(keyPassword.toCharArray());
133 pk = converter.getPrivateKey(((PKCS8EncryptedPrivateKeyInfo) object)
134 .decryptPrivateKeyInfo(pkcs8InputDecryptorProvider));
135 } else {
136 logger.debug("Unable to handle PEM object of type {} as a encrypted key", object.getClass());
137 }
138 }
139
140
141 if (pk == null) {
142 object = pemParser.readObject();
143 }
144 }
145
146 if (pk == null) {
147 if (logger.isDebugEnabled()) {
148 logger.debug("No key found");
149 }
150 }
151
152 return pk;
153 } finally {
154 if (pemParser != null) {
155 try {
156 pemParser.close();
157 } catch (Exception exception) {
158 logger.debug("Failed closing pem parser", exception);
159 }
160 }
161 }
162 }
163
164 private static PEMParser newParser(File keyFile) throws FileNotFoundException {
165 return new PEMParser(new FileReader(keyFile));
166 }
167
168 private static PEMParser newParser(InputStream keyInputStream) {
169 return new PEMParser(new InputStreamReader(keyInputStream, CharsetUtil.US_ASCII));
170 }
171
172 private BouncyCastlePemReader() { }
173 }