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.buffer.UnpooledByteBufAllocator;
19 import io.netty.internal.tcnative.SSL;
20 import io.netty.internal.tcnative.SSLCredential;
21 import io.netty.util.internal.ObjectUtil;
22
23 import java.security.PrivateKey;
24 import java.security.cert.X509Certificate;
25
26 import static io.netty.handler.ssl.OpenSslCredential.CredentialType;
27 import static io.netty.util.internal.ObjectUtil.checkNotNull;
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 public final class OpenSslCredentialBuilder {
53
54 private PrivateKey privateKey;
55 private OpenSslPrivateKey openSslPrivateKey;
56 private X509Certificate[] certificateChain;
57 private byte[] trustAnchorId;
58 private boolean mustMatchIssuer;
59
60 private OpenSslCredentialBuilder(PrivateKey privateKey, X509Certificate[] certificateChain) {
61 this.privateKey = checkNotNull(privateKey, "privateKey");
62 this.certificateChain = checkNotNull(certificateChain, "certificateChain").clone();
63 ObjectUtil.checkNonEmpty(this.certificateChain, "certificateChain");
64 }
65
66 private OpenSslCredentialBuilder(OpenSslPrivateKey openSslPrivateKey, X509Certificate[] certificateChain) {
67 this.openSslPrivateKey = checkNotNull(openSslPrivateKey, "privateKey");
68 this.certificateChain = checkNotNull(certificateChain, "certificateChain").clone();
69 ObjectUtil.checkNonEmpty(this.certificateChain, "certificateChain");
70 }
71
72
73
74
75
76
77
78
79 public static OpenSslCredentialBuilder forX509(PrivateKey privateKey, X509Certificate... certificateChain) {
80 return new OpenSslCredentialBuilder(privateKey, certificateChain);
81 }
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98 public OpenSslCredentialBuilder trustAnchorId(byte[] trustAnchorId) {
99 this.trustAnchorId = checkNotNull(trustAnchorId, "trustAnchorId").clone();
100 return this;
101 }
102
103
104
105
106
107
108
109 public OpenSslCredentialBuilder mustMatchIssuer(boolean mustMatchIssuer) {
110 this.mustMatchIssuer = mustMatchIssuer;
111 return this;
112 }
113
114
115
116
117
118
119
120 public OpenSslCredential build() {
121 OpenSsl.ensureAvailability();
122
123 if (!OpenSslCredential.isAvailable()) {
124 throw new UnsupportedOperationException("SSL_CREDENTIAL API is not supported");
125 }
126
127 long credentialPtr = 0;
128 long certChainPtr = 0;
129 long privateKeyPtr = 0;
130
131 try {
132
133 credentialPtr = createCredential();
134
135
136 privateKeyPtr = getPrivateKeyPointer();
137 SSLCredential.setPrivateKey(credentialPtr, privateKeyPtr);
138
139
140 certChainPtr = createCertChainPointer();
141 SSLCredential.setCertChain(credentialPtr, certChainPtr);
142
143
144 if (trustAnchorId != null) {
145 SSLCredential.setTrustAnchorId(credentialPtr, trustAnchorId);
146 }
147
148 if (mustMatchIssuer) {
149 SSLCredential.setMustMatchIssuer(credentialPtr, true);
150 }
151
152
153 long finalPtr = credentialPtr;
154 credentialPtr = 0;
155 return new DefaultOpenSslCredential(finalPtr, CredentialType.X509);
156 } catch (Exception e) {
157 throw new IllegalStateException("Failed to build SSL credential", e);
158 } finally {
159
160 if (credentialPtr != 0) {
161 try {
162 SSLCredential.free(credentialPtr);
163 } catch (Exception e) {
164
165 }
166 }
167 if (certChainPtr != 0) {
168 SSL.freeX509Chain(certChainPtr);
169 }
170 if (privateKeyPtr != 0 && privateKey != null) {
171
172 SSL.freePrivateKey(privateKeyPtr);
173 }
174 }
175 }
176
177 private long createCredential() throws Exception {
178 return SSLCredential.newX509();
179 }
180
181 private long getPrivateKeyPointer() throws Exception {
182 if (openSslPrivateKey != null) {
183 return openSslPrivateKey.privateKeyAddress();
184 }
185
186 if (privateKey == null) {
187 throw new IllegalStateException("No private key specified");
188 }
189
190
191 long bio = ReferenceCountedOpenSslContext.toBIO(
192 UnpooledByteBufAllocator.DEFAULT, privateKey);
193 try {
194 return SSL.parsePrivateKey(bio, null);
195 } finally {
196 SSL.freeBIO(bio);
197 }
198 }
199
200 private long createCertChainPointer() throws Exception {
201
202 try {
203 long bio = ReferenceCountedOpenSslContext.toBIO(
204 UnpooledByteBufAllocator.DEFAULT, certificateChain);
205 try {
206 return SSL.parseX509Chain(bio);
207 } finally {
208 SSL.freeBIO(bio);
209 }
210 } catch (Exception e) {
211 throw new IllegalStateException("Failed to encode certificate chain", e);
212 }
213 }
214 }