1 module hunt.net.secure.conscrypt.Conscrypt;
2 
3 // dfmt off
4 version(WITH_HUNT_SECURITY):
5 // dfmt on
6 
7 import hunt.net.secure.conscrypt.AbstractConscryptEngine;
8 import hunt.net.secure.conscrypt.ApplicationProtocolSelector;
9 import hunt.net.secure.conscrypt.NativeConstants;
10 
11 import hunt.net.ssl.SSLEngine;
12 
13 
14 import hunt.net.Exceptions;
15 import hunt.Exceptions;
16 
17 /**
18  * Core API for creating and configuring all Conscrypt types.
19  */
20 
21 final class Conscrypt {
22     private this() {}
23 
24     /**
25      * Returns {@code true} if the Conscrypt native library has been successfully loaded.
26      */
27     static bool isAvailable() {
28         try {
29             checkAvailability();
30             return true;
31         } catch (Exception e) {
32             return false;
33         }
34     }
35 
36     /**
37      * Checks that the Conscrypt support is available for the system.
38      *
39      * @throws UnsatisfiedLinkError if unavailable
40      */
41     static void checkAvailability() {
42         // NativeCrypto.checkAvailability();
43     }
44 
45     /**
46      * Indicates whether the given {@link Provider} was created by this distribution of Conscrypt.
47      */
48     // static bool isConscrypt(Provider provider) {
49     //     return provider instanceof OpenSSLProvider;
50     // }
51 
52     /**
53      * Constructs a new {@link Provider} with the default name.
54      */
55     // static Provider newProvider() {
56     //     checkAvailability();
57     //     return new OpenSSLProvider();
58     // }
59 
60     /**
61      * Constructs a new {@link Provider} with the given name.
62      */
63     // static Provider newProvider(string providerName) {
64     //     checkAvailability();
65     //     return new OpenSSLProvider(providerName);
66     // }
67 
68     /**
69      * Returns the maximum length (in bytes) of an encrypted packet.
70      */
71     static int maxEncryptedPacketLength() {
72         return NativeConstants.SSL3_RT_MAX_PACKET_SIZE;
73     }
74 
75     // /**
76     //  * Gets the default X.509 trust manager.
77     //  */
78     // @ExperimentalApi
79     // static X509TrustManager getDefaultX509TrustManager()  {
80     //     checkAvailability();
81     //     return SSLParametersImpl.getDefaultX509TrustManager();
82     // }
83 
84     // /**
85     //  * Indicates whether the given {@link SSLContext} was created by this distribution of Conscrypt.
86     //  */
87     // static bool isConscrypt(SSLContext context) {
88     //     return context.getProvider() instanceof OpenSSLProvider;
89     // }
90 
91     // /**
92     //  * Constructs a new instance of the preferred {@link SSLContextSpi}.
93     //  */
94     // static SSLContextSpi newPreferredSSLContextSpi() {
95     //     checkAvailability();
96     //     return OpenSSLContextImpl.getPreferred();
97     // }
98 
99     // /**
100     //  * Sets the client-side persistent cache to be used by the context.
101     //  */
102     // static void setClientSessionCache(SSLContext context, SSLClientSessionCache cache) {
103     //     SSLSessionContext clientContext = context.getClientSessionContext();
104     //     if (!(clientContext instanceof ClientSessionContext)) {
105     //         throw new IllegalArgumentException(
106     //                 "Not a conscrypt client context: " ~ clientContext.getClass().getName());
107     //     }
108     //     ((ClientSessionContext) clientContext).setPersistentCache(cache);
109     // }
110 
111     // /**
112     //  * Sets the server-side persistent cache to be used by the context.
113     //  */
114     // static void setServerSessionCache(SSLContext context, SSLServerSessionCache cache) {
115     //     SSLSessionContext serverContext = context.getServerSessionContext();
116     //     if (!(serverContext instanceof ServerSessionContext)) {
117     //         throw new IllegalArgumentException(
118     //                 "Not a conscrypt client context: " ~ serverContext.getClass().getName());
119     //     }
120     //     ((ServerSessionContext) serverContext).setPersistentCache(cache);
121     // }
122 
123     /**
124      * Indicates whether the given {@link SSLSocketFactory} was created by this distribution of
125      * Conscrypt.
126      */
127     // static bool isConscrypt(SSLSocketFactory factory) {
128     //     return typeid(factory) == typeid(OpenSSLSocketFactoryImpl);
129     // }
130 
131     // private static OpenSSLSocketFactoryImpl toConscrypt(SSLSocketFactory factory) {
132     //     if (!isConscrypt(factory)) {
133     //         throw new IllegalArgumentException(
134     //                 "Not a conscrypt socket factory: " ~ factory.getClass().getName());
135     //     }
136     //     return (OpenSSLSocketFactoryImpl) factory;
137     // }
138 
139     // /**
140     //  * Configures the default socket to be created for all socket factory instances.
141     //  */
142     // @ExperimentalApi
143     // static void setUseEngineSocketByDefault(bool useEngineSocket) {
144     //     OpenSSLSocketFactoryImpl.setUseEngineSocketByDefault(useEngineSocket);
145     //     OpenSSLServerSocketFactoryImpl.setUseEngineSocketByDefault(useEngineSocket);
146     // }
147 
148     // /**
149     //  * Configures the socket to be created for the given socket factory instance.
150     //  */
151     // @ExperimentalApi
152     // static void setUseEngineSocket(SSLSocketFactory factory, bool useEngineSocket) {
153     //     toConscrypt(factory).setUseEngineSocket(useEngineSocket);
154     // }
155 
156     // /**
157     //  * Indicates whether the given {@link SSLServerSocketFactory} was created by this distribution
158     //  * of Conscrypt.
159     //  */
160     // static bool isConscrypt(SSLServerSocketFactory factory) {
161     //     return factory instanceof OpenSSLServerSocketFactoryImpl;
162     // }
163 
164     // private static OpenSSLServerSocketFactoryImpl toConscrypt(SSLServerSocketFactory factory) {
165     //     if (!isConscrypt(factory)) {
166     //         throw new IllegalArgumentException(
167     //                 "Not a conscrypt server socket factory: " ~ factory.getClass().getName());
168     //     }
169     //     return (OpenSSLServerSocketFactoryImpl) factory;
170     // }
171 
172     // /**
173     //  * Configures the socket to be created for the given server socket factory instance.
174     //  */
175     // @ExperimentalApi
176     // static void setUseEngineSocket(SSLServerSocketFactory factory, bool useEngineSocket) {
177     //     toConscrypt(factory).setUseEngineSocket(useEngineSocket);
178     // }
179 
180     // /**
181     //  * Indicates whether the given {@link SSLSocket} was created by this distribution of Conscrypt.
182     //  */
183     // static bool isConscrypt(SSLSocket socket) {
184     //     return socket instanceof AbstractConscryptSocket;
185     // }
186 
187     // private static AbstractConscryptSocket toConscrypt(SSLSocket socket) {
188     //     if (!isConscrypt(socket)) {
189     //         throw new IllegalArgumentException(
190     //                 "Not a conscrypt socket: " ~ socket.getClass().getName());
191     //     }
192     //     return (AbstractConscryptSocket) socket;
193     // }
194 
195     // /**
196     //  * This method enables Server Name Indication (SNI) and overrides the hostname supplied
197     //  * during socket creation.  If the hostname is not a valid SNI hostname, the SNI extension
198     //  * will be omitted from the handshake.
199     //  *
200     //  * @param socket the socket
201     //  * @param hostname the desired SNI hostname, or null to disable
202     //  */
203     // static void setHostname(SSLSocket socket, string hostname) {
204     //     toConscrypt(socket).setHostname(hostname);
205     // }
206 
207     // /**
208     //  * Returns either the hostname supplied during socket creation or via
209     //  * {@link #setHostname(SSLSocket, string)}. No DNS resolution is attempted before
210     //  * returning the hostname.
211     //  */
212     // static string getHostname(SSLSocket socket) {
213     //     return toConscrypt(socket).getHostname();
214     // }
215 
216     // /**
217     //  * This method attempts to create a textual representation of the peer host or IP. Does
218     //  * not perform a reverse DNS lookup. This is typically used during session creation.
219     //  */
220     // static string getHostnameOrIP(SSLSocket socket) {
221     //     return toConscrypt(socket).getHostnameOrIP();
222     // }
223 
224     // /**
225     //  * This method enables session ticket support.
226     //  *
227     //  * @param socket the socket
228     //  * @param useSessionTickets True to enable session tickets
229     //  */
230     // static void setUseSessionTickets(SSLSocket socket, bool useSessionTickets) {
231     //     toConscrypt(socket).setUseSessionTickets(useSessionTickets);
232     // }
233 
234     // /**
235     //  * Enables/disables TLS Channel ID for the given server-side socket.
236     //  *
237     //  * <p>This method needs to be invoked before the handshake starts.
238     //  *
239     //  * @param socket the socket
240     //  * @param enabled Whether to enable channel ID.
241     //  * @throws IllegalStateException if this is a client socket or if the handshake has already
242     //  * started.
243     //  */
244     // static void setChannelIdEnabled(SSLSocket socket, bool enabled) {
245     //     toConscrypt(socket).setChannelIdEnabled(enabled);
246     // }
247 
248     // /**
249     //  * Gets the TLS Channel ID for the given server-side socket. Channel ID is only available
250     //  * once the handshake completes.
251     //  *
252     //  * @param socket the socket
253     //  * @return channel ID or {@code null} if not available.
254     //  * @throws IllegalStateException if this is a client socket or if the handshake has not yet
255     //  * completed.
256     //  * @throws SSLException if channel ID is available but could not be obtained.
257     //  */
258     // static byte[] getChannelId(SSLSocket socket) {
259     //     return toConscrypt(socket).getChannelId();
260     // }
261 
262     // /**
263     //  * Sets the {@link PrivateKey} to be used for TLS Channel ID by this client socket.
264     //  *
265     //  * <p>This method needs to be invoked before the handshake starts.
266     //  *
267     //  * @param socket the socket
268     //  * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key
269     //  * (disables TLS Channel ID).
270     //  * The private key must be an Elliptic Curve (EC) key based on the NIST P-256 curve (aka
271     //  * SECG secp256r1 or ANSI
272     //  * X9.62 prime256v1).
273     //  * @throws IllegalStateException if this is a server socket or if the handshake has already
274     //  * started.
275     //  */
276     // static void setChannelIdPrivateKey(SSLSocket socket, PrivateKey privateKey) {
277     //     toConscrypt(socket).setChannelIdPrivateKey(privateKey);
278     // }
279 
280     // /**
281     //  * Returns the ALPN protocol agreed upon by client and server.
282     //  *
283     //  * @param socket the socket
284     //  * @return the selected protocol or {@code null} if no protocol was agreed upon.
285     //  */
286     // static string getApplicationProtocol(SSLSocket socket) {
287     //     return toConscrypt(socket).getApplicationProtocol();
288     // }
289 
290     /**
291      * Sets an application-provided ALPN protocol selector. If provided, this will override
292      * the list of protocols set by {@link #setApplicationProtocols(SSLSocket, string[])}.
293      *
294      * @param socket the socket
295      * @param selector the ALPN protocol selector
296      */
297     // static void setApplicationProtocolSelector(SSLSocket socket,
298     //     ApplicationProtocolSelector selector) {
299     //     toConscrypt(socket).setApplicationProtocolSelector(selector);
300     // }
301 
302     // /**
303     //  * Sets the application-layer protocols (ALPN) in prioritization order.
304     //  *
305     //  * @param socket the socket being configured
306     //  * @param protocols the protocols in descending order of preference. If empty, no protocol
307     //  * indications will be used. This array will be copied.
308     //  * @throws IllegalArgumentException - if protocols is null, or if any element in a non-empty
309     //  * array is null or an empty (zero-length) string
310     //  */
311     // static void setApplicationProtocols(SSLSocket socket, string[] protocols) {
312     //     toConscrypt(socket).setApplicationProtocols(protocols);
313     // }
314 
315     // /**
316     //  * Gets the application-layer protocols (ALPN) in prioritization order.
317     //  *
318     //  * @param socket the socket
319     //  * @return the protocols in descending order of preference, or an empty array if protocol
320     //  * indications are not being used. Always returns a new array.
321     //  */
322     // static string[] getApplicationProtocols(SSLSocket socket) {
323     //     return toConscrypt(socket).getApplicationProtocols();
324     // }
325 
326     // /**
327     //  * Returns the tls-unique channel binding value for this connection, per RFC 5929.  This
328     //  * will return {@code null} if there is no such value available, such as if the handshake
329     //  * has not yet completed or this connection is closed.
330     //  */
331     // static byte[] getTlsUnique(SSLSocket socket) {
332     //     return toConscrypt(socket).getTlsUnique();
333     // }
334 
335     // /**
336     //  * Enables token binding parameter negotiation on this socket, or disables it if an
337     //  * empty set of parameters are provided.
338     //  *
339     //  * <p>This method needs to be invoked before the handshake starts.
340     //  *
341     //  * <p>Token binding is currently an Internet Draft that's subject to change, so the
342     //  * current implementation may not be compatible with future changes in the protocol.
343     //  *
344     //  * @param params a list of Token Binding key parameters in descending order of preference,
345     //  * as described in draft-ietf-tokbind-negotiation-09.
346     //  * @throws IllegalStateException if the handshake has already started.
347     //  * @throws SSLException if the setting could not be applied.
348     //  */
349     // @ExperimentalApi
350     // static void setTokenBindingParams(SSLSocket socket, int... params) {
351     //     toConscrypt(socket).setTokenBindingParams(params);
352     // }
353 
354     // /**
355     //  * Returns the token binding parameters that were negotiated during the handshake, or -1 if
356     //  * token binding parameters were not negotiated, the handshake has not yet completed,
357     //  * or the connection has been closed.
358     //  */
359     // @ExperimentalApi
360     // static int getTokenBindingParams(SSLSocket socket) {
361     //     return toConscrypt(socket).getTokenBindingParams();
362     // }
363 
364     // /**
365     //  * Exports a value derived from the TLS master secret as described in RFC 5705.
366     //  *
367     //  * @param label the label to use in calculating the exported value.  This must be
368     //  * an ASCII-only string.
369     //  * @param context the application-specific context value to use in calculating the
370     //  * exported value.  This may be {@code null} to use no application context, which is
371     //  * treated differently than an empty byte array.
372     //  * @param length the number of bytes of keying material to return.
373     //  * @return a value of the specified length, or {@code null} if the handshake has not yet
374     //  * completed or the connection has been closed.
375     //  * @throws SSLException if the value could not be exported.
376     //  */
377     // static byte[] exportKeyingMaterial(SSLSocket socket, string label, byte[] context,
378     //         int length) {
379     //     return toConscrypt(socket).exportKeyingMaterial(label, context, length);
380     // }
381 
382     /**
383      * Indicates whether the given {@link SSLEngine} was created by this distribution of Conscrypt.
384      */
385     static bool isConscrypt(SSLEngine engine) {
386         AbstractConscryptEngine e = cast(AbstractConscryptEngine)engine;
387         return e !is null;
388         // return typeid(engine) == typeid(AbstractConscryptEngine);
389     }
390 
391     private static AbstractConscryptEngine toConscrypt(SSLEngine engine) {
392         if (!isConscrypt(engine)) {
393             throw new IllegalArgumentException(
394                     "Not a conscrypt engine: " ~ typeid(engine).name);
395         }
396         return cast(AbstractConscryptEngine) engine;
397     }
398 
399     // /**
400     //  * Provides the given engine with the provided bufferAllocator.
401     //  */
402     // @ExperimentalApi
403     // static void setBufferAllocator(SSLEngine engine, BufferAllocator bufferAllocator) {
404     //     toConscrypt(engine).setBufferAllocator(bufferAllocator);
405     // }
406 
407     // /**
408     //  * Configures the default {@link BufferAllocator} to be used by all future
409     //  * {@link SSLEngine} instances from this provider.
410     //  */
411     // @ExperimentalApi
412     // static void setDefaultBufferAllocator(BufferAllocator bufferAllocator) {
413     //     ConscryptEngine.setDefaultBufferAllocator(bufferAllocator);
414     // }
415 
416     // /**
417     //  * This method enables Server Name Indication (SNI) and overrides the hostname supplied
418     //  * during engine creation.
419     //  *
420     //  * @param engine the engine
421     //  * @param hostname the desired SNI hostname, or {@code null} to disable
422     //  */
423     // static void setHostname(SSLEngine engine, string hostname) {
424     //     toConscrypt(engine).setHostname(hostname);
425     // }
426 
427     // /**
428     //  * Returns either the hostname supplied during socket creation or via
429     //  * {@link #setHostname(SSLEngine, string)}. No DNS resolution is attempted before
430     //  * returning the hostname.
431     //  */
432     // static string getHostname(SSLEngine engine) {
433     //     return toConscrypt(engine).getHostname();
434     // }
435 
436     // /**
437     //  * Returns the maximum overhead, in bytes, of sealing a record with SSL.
438     //  */
439     // static int maxSealOverhead(SSLEngine engine) {
440     //     return toConscrypt(engine).maxSealOverhead();
441     // }
442 
443     /**
444      * Sets a listener on the given engine for completion of the TLS handshake
445      */
446     static void setHandshakeListener(SSLEngine engine, HandshakeListener handshakeListener) {
447         toConscrypt(engine).setHandshakeListener(handshakeListener);
448     }
449 
450     // /**
451     //  * Enables/disables TLS Channel ID for the given server-side engine.
452     //  *
453     //  * <p>This method needs to be invoked before the handshake starts.
454     //  *
455     //  * @param engine the engine
456     //  * @param enabled Whether to enable channel ID.
457     //  * @throws IllegalStateException if this is a client engine or if the handshake has already
458     //  * started.
459     //  */
460     // static void setChannelIdEnabled(SSLEngine engine, bool enabled) {
461     //     toConscrypt(engine).setChannelIdEnabled(enabled);
462     // }
463 
464     // /**
465     //  * Gets the TLS Channel ID for the given server-side engine. Channel ID is only available
466     //  * once the handshake completes.
467     //  *
468     //  * @param engine the engine
469     //  * @return channel ID or {@code null} if not available.
470     //  * @throws IllegalStateException if this is a client engine or if the handshake has not yet
471     //  * completed.
472     //  * @throws SSLException if channel ID is available but could not be obtained.
473     //  */
474     // static byte[] getChannelId(SSLEngine engine) {
475     //     return toConscrypt(engine).getChannelId();
476     // }
477 
478     // /**
479     //  * Sets the {@link PrivateKey} to be used for TLS Channel ID by this client engine.
480     //  *
481     //  * <p>This method needs to be invoked before the handshake starts.
482     //  *
483     //  * @param engine the engine
484     //  * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key
485     //  * (disables TLS Channel ID).
486     //  * The private key must be an Elliptic Curve (EC) key based on the NIST P-256 curve (aka
487     //  * SECG secp256r1 or ANSI X9.62 prime256v1).
488     //  * @throws IllegalStateException if this is a server engine or if the handshake has already
489     //  * started.
490     //  */
491     // static void setChannelIdPrivateKey(SSLEngine engine, PrivateKey privateKey) {
492     //     toConscrypt(engine).setChannelIdPrivateKey(privateKey);
493     // }
494 
495     // /**
496     //  * Extended unwrap method for multiple source and destination buffers.
497     //  *
498     //  * @param engine the target engine for the unwrap
499     //  * @param srcs the source buffers
500     //  * @param dsts the destination buffers
501     //  * @return the result of the unwrap operation
502     //  * @throws SSLException thrown if an SSL error occurred
503     //  */
504     // static SSLEngineResult unwrap(SSLEngine engine, final ByteBuffer[] srcs,
505     //         final ByteBuffer[] dsts) {
506     //     return toConscrypt(engine).unwrap(srcs, dsts);
507     // }
508 
509     // /**
510     //  * Exteneded unwrap method for multiple source and destination buffers.
511     //  *
512     //  * @param engine the target engine for the unwrap.
513     //  * @param srcs the source buffers
514     //  * @param srcsOffset the offset in the {@code srcs} array of the first source buffer
515     //  * @param srcsLength the number of source buffers starting at {@code srcsOffset}
516     //  * @param dsts the destination buffers
517     //  * @param dstsOffset the offset in the {@code dsts} array of the first destination buffer
518     //  * @param dstsLength the number of destination buffers starting at {@code dstsOffset}
519     //  * @return the result of the unwrap operation
520     //  * @throws SSLException thrown if an SSL error occurred
521     //  */
522     // static SSLEngineResult unwrap(SSLEngine engine, final ByteBuffer[] srcs, int srcsOffset,
523     //         final int srcsLength, final ByteBuffer[] dsts, final int dstsOffset,
524     //         final int dstsLength) {
525     //     return toConscrypt(engine).unwrap(
526     //             srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
527     // }
528 
529     // /**
530     //  * This method enables session ticket support.
531     //  *
532     //  * @param engine the engine
533     //  * @param useSessionTickets True to enable session tickets
534     //  */
535     // static void setUseSessionTickets(SSLEngine engine, bool useSessionTickets) {
536     //     toConscrypt(engine).setUseSessionTickets(useSessionTickets);
537     // }
538 
539     // /**
540     //  * Sets the application-layer protocols (ALPN) in prioritization order.
541     //  *
542     //  * @param engine the engine being configured
543     //  * @param protocols the protocols in descending order of preference. If empty, no protocol
544     //  * indications will be used.  This array will be copied.
545     //  * @throws IllegalArgumentException - if protocols is null, or if any element in a non-empty
546     //  * array is null or an empty (zero-length) string
547     //  */
548     static void setApplicationProtocols(SSLEngine engine, string[] protocols) {
549         toConscrypt(engine).setApplicationProtocols(protocols);
550     }
551 
552     /**
553      * Gets the application-layer protocols (ALPN) in prioritization order.
554      *
555      * @param engine the engine
556      * @return the protocols in descending order of preference, or an empty array if protocol
557      * indications are not being used. Always returns a new array.
558      */
559     static string[] getApplicationProtocols(SSLEngine engine) {
560         return toConscrypt(engine).getApplicationProtocols();
561     }
562 
563     /**
564      * Sets an application-provided ALPN protocol selector. If provided, this will override
565      * the list of protocols set by {@link #setApplicationProtocols(SSLEngine, string[])}.
566      *
567      * @param engine the engine
568      * @param selector the ALPN protocol selector
569      */
570     static void setApplicationProtocolSelector(SSLEngine engine,
571         ApplicationProtocolSelector selector) {
572         toConscrypt(engine).setApplicationProtocolSelector(selector);
573     }
574 
575     /**
576      * Returns the ALPN protocol agreed upon by client and server.
577      *
578      * @param engine the engine
579      * @return the selected protocol or {@code null} if no protocol was agreed upon.
580      */
581     static string getApplicationProtocol(SSLEngine engine) {
582         return toConscrypt(engine).getApplicationProtocol();
583     }
584 
585     // /**
586     //  * Returns the tls-unique channel binding value for this connection, per RFC 5929.  This
587     //  * will return {@code null} if there is no such value available, such as if the handshake
588     //  * has not yet completed or this connection is closed.
589     //  */
590     // static byte[] getTlsUnique(SSLEngine engine) {
591     //     return toConscrypt(engine).getTlsUnique();
592     // }
593 
594     // /**
595     //  * Enables token binding parameter negotiation on this engine, or disables it if an
596     //  * empty set of parameters are provided.
597     //  *
598     //  * <p>This method needs to be invoked before the handshake starts.
599     //  *
600     //  * @param params a list of Token Binding key parameters in descending order of preference,
601     //  * as described in draft-ietf-tokbind-negotiation-09.
602     //  * @throws IllegalStateException if the handshake has already started.
603     //  * @throws SSLException if the setting could not be applied.
604     //  */
605     // static void setTokenBindingParams(SSLEngine engine, int... params) {
606     //     toConscrypt(engine).setTokenBindingParams(params);
607     // }
608 
609     // /**
610     //  * Returns the token binding parameters that were negotiated during the handshake, or -1 if
611     //  * token binding parameters were not negotiated, the handshake has not yet completed,
612     //  * or the connection has been closed.
613     //  */
614     // static int getTokenBindingParams(SSLEngine engine) {
615     //     return toConscrypt(engine).getTokenBindingParams();
616     // }
617 
618     // /**
619     //  * Exports a value derived from the TLS master secret as described in RFC 5705.
620     //  *
621     //  * @param label the label to use in calculating the exported value.  This must be
622     //  * an ASCII-only string.
623     //  * @param context the application-specific context value to use in calculating the
624     //  * exported value.  This may be {@code null} to use no application context, which is
625     //  * treated differently than an empty byte array.
626     //  * @param length the number of bytes of keying material to return.
627     //  * @return a value of the specified length, or {@code null} if the handshake has not yet
628     //  * completed or the connection has been closed.
629     //  * @throws SSLException if the value could not be exported.
630     //  */
631     // static byte[] exportKeyingMaterial(SSLEngine engine, string label, byte[] context,
632     //         int length) {
633     //     return toConscrypt(engine).exportKeyingMaterial(label, context, length);
634     // }
635 }