45
45
46
46
import javax .net .ssl .KeyManager ;
47
47
import javax .net .ssl .SSLEngine ;
48
+ import javax .net .ssl .SSLParameters ;
48
49
import javax .net .ssl .SSLSessionContext ;
49
50
import javax .net .ssl .TrustManager ;
50
51
import javax .net .ssl .X509ExtendedKeyManager ;
53
54
import org .jruby .Ruby ;
54
55
import org .jruby .RubyArray ;
55
56
import org .jruby .RubyClass ;
57
+ import org .jruby .RubyString ;
56
58
import org .jruby .RubyFixnum ;
57
59
import org .jruby .RubyHash ;
58
60
import org .jruby .RubyInteger ;
59
61
import org .jruby .RubyModule ;
60
62
import org .jruby .RubyNumeric ;
61
63
import org .jruby .RubyObject ;
62
64
import org .jruby .RubySymbol ;
65
+ import org .jruby .RubyProc ;
63
66
import org .jruby .anno .JRubyMethod ;
64
67
import org .jruby .common .IRubyWarnings .ID ;
65
68
import org .jruby .runtime .Arity ;
@@ -242,6 +245,8 @@ public static void createSSLContext(final Ruby runtime, final RubyModule SSL) {
242
245
SSLContext .addReadWriteAttribute (context , "tmp_dh_callback" );
243
246
SSLContext .addReadWriteAttribute (context , "servername_cb" );
244
247
SSLContext .addReadWriteAttribute (context , "renegotiation_cb" );
248
+ SSLContext .addReadWriteAttribute (context , "alpn_protocols" );
249
+ SSLContext .addReadWriteAttribute (context , "alpn_select_cb" );
245
250
246
251
SSLContext .defineAlias ("ssl_timeout" , "timeout" );
247
252
SSLContext .defineAlias ("ssl_timeout=" , "timeout=" );
@@ -451,6 +456,29 @@ public IRubyObject setup(final ThreadContext context) {
451
456
// SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb);
452
457
}
453
458
459
+ final String [] alpnProtocols ;
460
+
461
+ value = getInstanceVariable ("@alpn_protocols" );
462
+ if ( value != null && ! value .isNil () ) {
463
+ IRubyObject [] alpn_protocols = ((RubyArray ) value ).toJavaArrayMaybeUnsafe ();
464
+ String [] protocols = new String [alpn_protocols .length ];
465
+ for (int i = 0 ; i < protocols .length ; i ++) {
466
+ protocols [i ] = alpn_protocols [i ].convertToString ().asJavaString ();
467
+ }
468
+ alpnProtocols = protocols ;
469
+ } else {
470
+ alpnProtocols = null ;
471
+ }
472
+
473
+ final RubyProc alpnSelectCb ;
474
+ value = getInstanceVariable ("@alpn_select_cb" );
475
+ if ( value != null && ! value .isNil () ) {
476
+ alpnSelectCb = (RubyProc ) value ;
477
+ } else {
478
+ alpnSelectCb = null ;
479
+ }
480
+
481
+
454
482
// NOTE: no API under javax.net to support session get/new/remove callbacks
455
483
/*
456
484
val = ossl_sslctx_get_sess_id_ctx(self);
@@ -477,7 +505,8 @@ public IRubyObject setup(final ThreadContext context) {
477
505
*/
478
506
479
507
try {
480
- internalContext = createInternalContext (context , cert , key , store , clientCert , extraChainCert , verifyMode , timeout );
508
+ internalContext = createInternalContext (context , cert , key , store , clientCert , extraChainCert ,
509
+ verifyMode , timeout , alpnProtocols , alpnSelectCb );
481
510
}
482
511
catch (GeneralSecurityException e ) {
483
512
throw newSSLError (runtime , e );
@@ -505,7 +534,7 @@ private RubyArray matchedCiphersWithCache(final ThreadContext context) {
505
534
private RubyArray matchedCiphers (final ThreadContext context ) {
506
535
final Ruby runtime = context .runtime ;
507
536
try {
508
- final String [] supported = getSupportedCipherSuites (protocol );
537
+ final String [] supported = getSupportedCipherSuites (runtime , protocol );
509
538
final Collection <CipherStrings .Def > cipherDefs =
510
539
CipherStrings .matchingCiphers (this .ciphers , supported , false );
511
540
@@ -688,14 +717,48 @@ private static class CipherListCache {
688
717
}
689
718
}
690
719
691
- private static String [] getSupportedCipherSuites (final String protocol )
720
+ void setApplicationProtocolsOrSelector (final SSLEngine engine ) {
721
+ setApplicationProtocolSelector (engine );
722
+ setApplicationProtocols (engine );
723
+ }
724
+
725
+ private void setApplicationProtocolSelector (final SSLEngine engine ) {
726
+ final RubyProc alpn_select_cb = internalContext .alpnSelectCallback ;
727
+ if (alpn_select_cb != null ) {
728
+ engine .setHandshakeApplicationProtocolSelector ((_engine , protocols ) -> {
729
+ final Ruby runtime = getRuntime ();
730
+ IRubyObject [] rubyProtocols = new IRubyObject [protocols .size ()];
731
+ int i = 0 ; for (String protocol : protocols ) {
732
+ rubyProtocols [i ++] = runtime .newString (protocol );
733
+ }
734
+
735
+ IRubyObject [] args = new IRubyObject [] { RubyArray .newArray (runtime , rubyProtocols ) };
736
+ IRubyObject selected_protocol = alpn_select_cb .call (runtime .getCurrentContext (), args );
737
+ if (selected_protocol != null && !selected_protocol .isNil ()) {
738
+ return ((RubyString ) selected_protocol ).asJavaString ();
739
+ }
740
+ return null ; // callback returned nil - none of the advertised names are acceptable
741
+ });
742
+ }
743
+ }
744
+
745
+ private void setApplicationProtocols (final SSLEngine engine ) {
746
+ final String [] alpn_protocols = internalContext .alpnProtocols ;
747
+ if (alpn_protocols != null ) {
748
+ SSLParameters params = engine .getSSLParameters ();
749
+ params .setApplicationProtocols (alpn_protocols );
750
+ engine .setSSLParameters (params );
751
+ }
752
+ }
753
+
754
+ private static String [] getSupportedCipherSuites (Ruby runtime , final String protocol )
692
755
throws GeneralSecurityException {
693
- return dummySSLEngine (protocol ).getSupportedCipherSuites ();
756
+ return dummySSLEngine (runtime , protocol ).getSupportedCipherSuites ();
694
757
}
695
758
696
- private static SSLEngine dummySSLEngine (final String protocol ) throws GeneralSecurityException {
759
+ private static SSLEngine dummySSLEngine (Ruby runtime , final String protocol ) throws GeneralSecurityException {
697
760
javax .net .ssl .SSLContext sslContext = SecurityHelper .getSSLContext (protocol );
698
- sslContext .init (null , null , null );
761
+ sslContext .init (null , null , OpenSSL . getSecureRandom ( runtime ) );
699
762
return sslContext .createSSLEngine ();
700
763
}
701
764
@@ -899,8 +962,9 @@ static RubyClass _SSLContext(final Ruby runtime) {
899
962
private InternalContext createInternalContext (ThreadContext context ,
900
963
final X509Cert xCert , final PKey pKey , final Store store ,
901
964
final List <X509AuxCertificate > clientCert , final List <X509AuxCertificate > extraChainCert ,
902
- final int verifyMode , final int timeout ) throws NoSuchAlgorithmException , KeyManagementException {
903
- InternalContext internalContext = new InternalContext (xCert , pKey , store , clientCert , extraChainCert , verifyMode , timeout );
965
+ final int verifyMode , final int timeout ,
966
+ final String [] alpnProtocols , final RubyProc alpnSelectCb ) throws NoSuchAlgorithmException , KeyManagementException {
967
+ InternalContext internalContext = new InternalContext (xCert , pKey , store , clientCert , extraChainCert , verifyMode , timeout , alpnProtocols , alpnSelectCb );
904
968
internalContext .initSSLContext (context );
905
969
return internalContext ;
906
970
}
@@ -917,7 +981,9 @@ private class InternalContext {
917
981
final List <X509AuxCertificate > clientCert ,
918
982
final List <X509AuxCertificate > extraChainCert ,
919
983
final int verifyMode ,
920
- final int timeout ) throws NoSuchAlgorithmException {
984
+ final int timeout ,
985
+ final String [] alpnProtocols ,
986
+ final RubyProc alpnSelectCallback ) throws NoSuchAlgorithmException {
921
987
922
988
if ( pKey != null && xCert != null ) {
923
989
this .privateKey = pKey .getPrivateKey ();
@@ -935,6 +1001,8 @@ private class InternalContext {
935
1001
this .extraChainCert = extraChainCert ;
936
1002
this .verifyMode = verifyMode ;
937
1003
this .timeout = timeout ;
1004
+ this .alpnProtocols = alpnProtocols ;
1005
+ this .alpnSelectCallback = alpnSelectCallback ;
938
1006
939
1007
// initialize SSL context :
940
1008
@@ -982,6 +1050,9 @@ void initSSLContext(final ThreadContext context) throws KeyManagementException {
982
1050
983
1051
private final int timeout ;
984
1052
1053
+ private final String [] alpnProtocols ;
1054
+ private final RubyProc alpnSelectCallback ;
1055
+
985
1056
private final javax .net .ssl .SSLContext sslContext ;
986
1057
987
1058
// part of ssl_verify_cert_chain
0 commit comments