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 }