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      static native boolean SSLContext_setSessionIdContext(long context, byte[] sidCtx);
86  
87      static native void SSLContext_setSessionTicketKeys(long context, boolean enableCallback);
88  
89      static int SSLContext_set1_groups_list(long ctx, String... groups) {
90          if (groups == null) {
91              throw new NullPointerException("curves");
92          }
93          if (groups.length == 0) {
94              throw new IllegalArgumentException();
95          }
96          StringBuilder sb = new StringBuilder();
97          for (String group: groups) {
98              sb.append(group);
99              // Groups are separated by : as explained in the manpage.
100             sb.append(':');
101         }
102         sb.setLength(sb.length() - 1);
103         return SSLContext_set1_groups_list(ctx, sb.toString());
104     }
105 
106     static int SSLContext_set1_sigalgs_list(long ctx, String... sigalgs) {
107         if (sigalgs.length == 0) {
108             throw new IllegalArgumentException();
109         }
110         StringBuilder sb = new StringBuilder();
111         for (String sigalg: sigalgs) {
112             sb.append(sigalg);
113             // Groups are separated by : as explained in the manpage.
114             sb.append(':');
115         }
116         sb.setLength(sb.length() - 1);
117         return SSLContext_set1_sigalgs_list(ctx, sb.toString());
118     }
119 
120     private static native int SSLContext_set1_sigalgs_list(long context, String sigalgs);
121 
122     private static native int SSLContext_set1_groups_list(long context, String groups);
123     static native void SSLContext_free(long context);
124     static long SSL_new(long context, boolean server, String hostname) {
125         return SSL_new0(context, server, tlsExtHostName(hostname));
126     }
127     static native long SSL_new0(long context, boolean server, @Nullable String hostname);
128     static native void SSL_free(long ssl);
129 
130     static native Runnable SSL_getTask(long ssl);
131 
132     static native void SSL_cleanup(long ssl);
133 
134     static native long EVP_PKEY_parse(byte[] bytes, String pass);
135     static native void EVP_PKEY_free(long key);
136 
137     static native long CRYPTO_BUFFER_stack_new(long ssl, byte[][] bytes);
138     static native void CRYPTO_BUFFER_stack_free(long chain);
139 
140     @Nullable
141     static native String ERR_last_error();
142 
143     @Nullable
144     private static String tlsExtHostName(@Nullable String hostname) {
145         if (hostname != null && hostname.endsWith(".")) {
146             // Strip trailing dot if included.
147             // See https://github.com/netty/netty-tcnative/issues/400
148             hostname = hostname.substring(0, hostname.length() - 1);
149         }
150         return hostname;
151     }
152 
153     static X509Certificate[] certificates(byte[][] chain) {
154         X509Certificate[] peerCerts = new X509Certificate[chain.length];
155         for (int i = 0; i < peerCerts.length; i++) {
156             peerCerts[i] = new LazyX509Certificate(chain[i]);
157         }
158         return peerCerts;
159     }
160 
161     static byte[][] subjectNames(X509Certificate[] certificates) {
162         byte[][] subjectNames = new byte[certificates.length][];
163         for (int i = 0; i < certificates.length; i++) {
164             subjectNames[i] = certificates[i].getSubjectX500Principal().getEncoded();
165         }
166         return subjectNames;
167     }
168 
169     private BoringSSL() { }
170 }