View Javadoc
1   /*
2    * Copyright 2021 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.handler.codec.quic;
17  
18  import io.netty.handler.ssl.util.LazyX509Certificate;
19  import org.jetbrains.annotations.Nullable;
20  
21  import java.io.ByteArrayOutputStream;
22  import java.io.IOException;
23  import java.nio.charset.StandardCharsets;
24  import java.security.cert.X509Certificate;
25  
26  final class BoringSSL {
27  
28      static final int SSL_VERIFY_NONE = BoringSSLNativeStaticallyReferencedJniMethods.ssl_verify_none();
29      static final int SSL_VERIFY_FAIL_IF_NO_PEER_CERT = BoringSSLNativeStaticallyReferencedJniMethods
30              .ssl_verify_fail_if_no_peer_cert();
31      static final int SSL_VERIFY_PEER = BoringSSLNativeStaticallyReferencedJniMethods.ssl_verify_peer();
32      static final int X509_V_OK = BoringSSLNativeStaticallyReferencedJniMethods.x509_v_ok();
33      static final int X509_V_ERR_CERT_HAS_EXPIRED =
34              BoringSSLNativeStaticallyReferencedJniMethods.x509_v_err_cert_has_expired();
35      static final int X509_V_ERR_CERT_NOT_YET_VALID =
36              BoringSSLNativeStaticallyReferencedJniMethods.x509_v_err_cert_not_yet_valid();
37      static final int X509_V_ERR_CERT_REVOKED = BoringSSLNativeStaticallyReferencedJniMethods.x509_v_err_cert_revoked();
38      static final int X509_V_ERR_UNSPECIFIED = BoringSSLNativeStaticallyReferencedJniMethods.x509_v_err_unspecified();
39  
40      static long SSLContext_new(boolean server, String[] applicationProtocols,
41                                 BoringSSLHandshakeCompleteCallback handshakeCompleteCallback,
42                                 BoringSSLCertificateCallback certificateCallback,
43                                 BoringSSLCertificateVerifyCallback verifyCallback,
44                                 @Nullable BoringSSLTlsextServernameCallback servernameCallback,
45                                 @Nullable BoringSSLKeylogCallback keylogCallback,
46                                 @Nullable BoringSSLSessionCallback sessionCallback,
47                                 @Nullable BoringSSLPrivateKeyMethod privateKeyMethod,
48                                 BoringSSLSessionTicketCallback sessionTicketCallback,
49                                 int verifyMode,
50                                 byte[][] subjectNames) {
51          return SSLContext_new0(server, toWireFormat(applicationProtocols),
52                  handshakeCompleteCallback, certificateCallback, verifyCallback, servernameCallback,
53                  keylogCallback, sessionCallback, privateKeyMethod, sessionTicketCallback, verifyMode, subjectNames);
54      }
55  
56      private static byte @Nullable [] toWireFormat(String @Nullable [] applicationProtocols) {
57          if (applicationProtocols == null) {
58              return null;
59          }
60          try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
61              for (String p : applicationProtocols) {
62                  byte[] bytes = p.getBytes(StandardCharsets.US_ASCII);
63                  out.write(bytes.length);
64                  out.write(bytes);
65              }
66              return out.toByteArray();
67          } catch (IOException e) {
68              throw new IllegalStateException(e);
69          }
70      }
71  
72      static native long SSLContext_new();
73  
74      private static native long SSLContext_new0(boolean server,
75                                                 byte @Nullable [] applicationProtocols, Object handshakeCompleteCallback,
76                                                 Object certificateCallback, Object verifyCallback,
77                                                 @Nullable Object servernameCallback, @Nullable Object keylogCallback,
78                                                 @Nullable Object sessionCallback,
79                                                 @Nullable Object privateKeyMethod,
80                                                 Object sessionTicketCallback,
81                                                 int verifyDepth, byte[][] subjectNames);
82      static native void SSLContext_set_early_data_enabled(long context, boolean enabled);
83      static native long SSLContext_setSessionCacheSize(long context, long size);
84      static native long SSLContext_setSessionCacheTimeout(long context, long size);
85  
86      static native void SSLContext_setSessionTicketKeys(long context, boolean enableCallback);
87  
88      static int SSLContext_set1_groups_list(long ctx, String... groups) {
89          if (groups == null) {
90              throw new NullPointerException("curves");
91          }
92          if (groups.length == 0) {
93              throw new IllegalArgumentException();
94          }
95          StringBuilder sb = new StringBuilder();
96          for (String group: groups) {
97              sb.append(group);
98              // Groups are separated by : as explained in the manpage.
99              sb.append(':');
100         }
101         sb.setLength(sb.length() - 1);
102         return SSLContext_set1_groups_list(ctx, sb.toString());
103     }
104 
105     static int SSLContext_set1_sigalgs_list(long ctx, String... sigalgs) {
106         if (sigalgs.length == 0) {
107             throw new IllegalArgumentException();
108         }
109         StringBuilder sb = new StringBuilder();
110         for (String sigalg: sigalgs) {
111             sb.append(sigalg);
112             // Groups are separated by : as explained in the manpage.
113             sb.append(':');
114         }
115         sb.setLength(sb.length() - 1);
116         return SSLContext_set1_sigalgs_list(ctx, sb.toString());
117     }
118 
119     private static native int SSLContext_set1_sigalgs_list(long context, String sigalgs);
120 
121     private static native int SSLContext_set1_groups_list(long context, String groups);
122     static native void SSLContext_free(long context);
123     static long SSL_new(long context, boolean server, String hostname) {
124         return SSL_new0(context, server, tlsExtHostName(hostname));
125     }
126     static native long SSL_new0(long context, boolean server, @Nullable String hostname);
127     static native void SSL_free(long ssl);
128 
129     static native Runnable SSL_getTask(long ssl);
130 
131     static native void SSL_cleanup(long ssl);
132 
133     static native long EVP_PKEY_parse(byte[] bytes, String pass);
134     static native void EVP_PKEY_free(long key);
135 
136     static native long CRYPTO_BUFFER_stack_new(long ssl, byte[][] bytes);
137     static native void CRYPTO_BUFFER_stack_free(long chain);
138 
139     @Nullable
140     static native String ERR_last_error();
141 
142     @Nullable
143     private static String tlsExtHostName(@Nullable String hostname) {
144         if (hostname != null && hostname.endsWith(".")) {
145             // Strip trailing dot if included.
146             // See https://github.com/netty/netty-tcnative/issues/400
147             hostname = hostname.substring(0, hostname.length() - 1);
148         }
149         return hostname;
150     }
151 
152     static X509Certificate[] certificates(byte[][] chain) {
153         X509Certificate[] peerCerts = new X509Certificate[chain.length];
154         for (int i = 0; i < peerCerts.length; i++) {
155             peerCerts[i] = new LazyX509Certificate(chain[i]);
156         }
157         return peerCerts;
158     }
159 
160     static byte[][] subjectNames(X509Certificate[] certificates) {
161         byte[][] subjectNames = new byte[certificates.length][];
162         for (int i = 0; i < certificates.length; i++) {
163             subjectNames[i] = certificates[i].getSubjectX500Principal().getEncoded();
164         }
165         return subjectNames;
166     }
167 
168     private BoringSSL() { }
169 }