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.internal.tcnative.SSL;
19 import io.netty.internal.tcnative.SSLContext;
20 import io.netty.internal.tcnative.SessionTicketKey;
21 import io.netty.util.internal.ObjectUtil;
22
23 import javax.net.ssl.SSLSession;
24 import javax.net.ssl.SSLSessionContext;
25 import java.util.Arrays;
26 import java.util.Enumeration;
27 import java.util.Iterator;
28 import java.util.concurrent.locks.Lock;
29
30
31
32
33 public abstract class OpenSslSessionContext implements SSLSessionContext {
34
35 private final OpenSslSessionStats stats;
36
37
38
39
40 private final OpenSslKeyMaterialProvider provider;
41
42 final ReferenceCountedOpenSslContext context;
43
44 private final OpenSslSessionCache sessionCache;
45 private final long mask;
46
47
48
49
50
51 OpenSslSessionContext(ReferenceCountedOpenSslContext context, OpenSslKeyMaterialProvider provider, long mask,
52 OpenSslSessionCache cache) {
53 this.context = context;
54 this.provider = provider;
55 this.mask = mask;
56 stats = new OpenSslSessionStats(context);
57 sessionCache = cache;
58 SSLContext.setSSLSessionCache(context.ctx, cache);
59 }
60
61 final boolean useKeyManager() {
62 return provider != null;
63 }
64
65 @Override
66 public void setSessionCacheSize(int size) {
67 ObjectUtil.checkPositiveOrZero(size, "size");
68 sessionCache.setSessionCacheSize(size);
69 }
70
71 @Override
72 public int getSessionCacheSize() {
73 return sessionCache.getSessionCacheSize();
74 }
75
76 @Override
77 public void setSessionTimeout(int seconds) {
78 ObjectUtil.checkPositiveOrZero(seconds, "seconds");
79
80 Lock writerLock = context.ctxLock.writeLock();
81 writerLock.lock();
82 try {
83 SSLContext.setSessionCacheTimeout(context.ctx, seconds);
84 sessionCache.setSessionTimeout(seconds);
85 } finally {
86 writerLock.unlock();
87 }
88 }
89
90 @Override
91 public int getSessionTimeout() {
92 return sessionCache.getSessionTimeout();
93 }
94
95 @Override
96 public SSLSession getSession(byte[] bytes) {
97 return sessionCache.getSession(new OpenSslSessionId(bytes));
98 }
99
100 @Override
101 public Enumeration<byte[]> getIds() {
102 return new Enumeration<byte[]>() {
103 private final Iterator<OpenSslSessionId> ids = sessionCache.getIds().iterator();
104 @Override
105 public boolean hasMoreElements() {
106 return ids.hasNext();
107 }
108
109 @Override
110 public byte[] nextElement() {
111 return ids.next().cloneBytes();
112 }
113 };
114 }
115
116
117
118
119
120 @Deprecated
121 public void setTicketKeys(byte[] keys) {
122 if (keys.length % SessionTicketKey.TICKET_KEY_SIZE != 0) {
123 throw new IllegalArgumentException("keys.length % " + SessionTicketKey.TICKET_KEY_SIZE + " != 0");
124 }
125 SessionTicketKey[] tickets = new SessionTicketKey[keys.length / SessionTicketKey.TICKET_KEY_SIZE];
126 for (int i = 0, a = 0; i < tickets.length; i++) {
127 byte[] name = Arrays.copyOfRange(keys, a, SessionTicketKey.NAME_SIZE);
128 a += SessionTicketKey.NAME_SIZE;
129 byte[] hmacKey = Arrays.copyOfRange(keys, a, SessionTicketKey.HMAC_KEY_SIZE);
130 i += SessionTicketKey.HMAC_KEY_SIZE;
131 byte[] aesKey = Arrays.copyOfRange(keys, a, SessionTicketKey.AES_KEY_SIZE);
132 a += SessionTicketKey.AES_KEY_SIZE;
133 tickets[i] = new SessionTicketKey(name, hmacKey, aesKey);
134 }
135 Lock writerLock = context.ctxLock.writeLock();
136 writerLock.lock();
137 try {
138 SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET);
139 SSLContext.setSessionTicketKeys(context.ctx, tickets);
140 } finally {
141 writerLock.unlock();
142 }
143 }
144
145
146
147
148
149
150
151
152 public void setTicketKeys(OpenSslSessionTicketKey... keys) {
153 ObjectUtil.checkNotNull(keys, "keys");
154 SessionTicketKey[] ticketKeys = new SessionTicketKey[keys.length];
155 for (int i = 0; i < ticketKeys.length; i++) {
156 ticketKeys[i] = keys[i].key;
157 }
158 Lock writerLock = context.ctxLock.writeLock();
159 writerLock.lock();
160 try {
161 SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET);
162 if (ticketKeys.length > 0) {
163 SSLContext.setSessionTicketKeys(context.ctx, ticketKeys);
164 }
165 } finally {
166 writerLock.unlock();
167 }
168 }
169
170
171
172
173 public void setSessionCacheEnabled(boolean enabled) {
174 long mode = enabled ? mask | SSL.SSL_SESS_CACHE_NO_INTERNAL_LOOKUP |
175 SSL.SSL_SESS_CACHE_NO_INTERNAL_STORE : SSL.SSL_SESS_CACHE_OFF;
176 Lock writerLock = context.ctxLock.writeLock();
177 writerLock.lock();
178 try {
179 SSLContext.setSessionCacheMode(context.ctx, mode);
180 if (!enabled) {
181 sessionCache.clear();
182 }
183 } finally {
184 writerLock.unlock();
185 }
186 }
187
188
189
190
191 public boolean isSessionCacheEnabled() {
192 Lock readerLock = context.ctxLock.readLock();
193 readerLock.lock();
194 try {
195 return (SSLContext.getSessionCacheMode(context.ctx) & mask) != 0;
196 } finally {
197 readerLock.unlock();
198 }
199 }
200
201
202
203
204 public OpenSslSessionStats stats() {
205 return stats;
206 }
207
208
209
210
211 final void removeFromCache(OpenSslSessionId id) {
212 sessionCache.removeSessionWithId(id);
213 }
214
215 final boolean isInCache(OpenSslSessionId id) {
216 return sessionCache.containsSessionWithId(id);
217 }
218
219 boolean setSessionFromCache(long ssl, OpenSslSession session, String host, int port) {
220 return sessionCache.setSession(ssl, session, host, port);
221 }
222
223 final void destroy() {
224 if (provider != null) {
225 provider.destroy();
226 }
227 sessionCache.clear();
228 }
229 }