1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.quic;
17
18 import io.netty.handler.ssl.OpenSslCertificateException;
19 import org.jetbrains.annotations.Nullable;
20
21 import javax.net.ssl.X509ExtendedTrustManager;
22 import javax.net.ssl.X509TrustManager;
23 import java.security.cert.CertPathValidatorException;
24 import java.security.cert.CertificateExpiredException;
25 import java.security.cert.CertificateNotYetValidException;
26 import java.security.cert.CertificateRevokedException;
27 import java.security.cert.X509Certificate;
28
29 final class BoringSSLCertificateVerifyCallback {
30
31 private static final boolean TRY_USING_EXTENDED_TRUST_MANAGER;
32 static {
33 boolean tryUsingExtendedTrustManager;
34 try {
35 Class.forName(X509ExtendedTrustManager.class.getName());
36 tryUsingExtendedTrustManager = true;
37 } catch (Throwable cause) {
38 tryUsingExtendedTrustManager = false;
39 }
40 TRY_USING_EXTENDED_TRUST_MANAGER = tryUsingExtendedTrustManager;
41 }
42
43 private final QuicheQuicSslEngineMap engineMap;
44 private final X509TrustManager manager;
45
46 BoringSSLCertificateVerifyCallback(QuicheQuicSslEngineMap engineMap, @Nullable X509TrustManager manager) {
47 this.engineMap = engineMap;
48 this.manager = manager;
49 }
50
51 @SuppressWarnings("unused")
52 int verify(long ssl, byte[][] x509, String authAlgorithm) {
53 final QuicheQuicSslEngine engine = engineMap.get(ssl);
54 if (engine == null) {
55
56 return BoringSSL.X509_V_ERR_UNSPECIFIED;
57 }
58
59 if (manager == null) {
60 engineMap.remove(ssl);
61 return BoringSSL.X509_V_ERR_UNSPECIFIED;
62 }
63
64 X509Certificate[] peerCerts = BoringSSL.certificates(x509);
65 try {
66 if (engine.getUseClientMode()) {
67 if (TRY_USING_EXTENDED_TRUST_MANAGER && manager instanceof X509ExtendedTrustManager) {
68 ((X509ExtendedTrustManager) manager).checkServerTrusted(peerCerts, authAlgorithm, engine);
69 } else {
70 manager.checkServerTrusted(peerCerts, authAlgorithm);
71 }
72 } else {
73 if (TRY_USING_EXTENDED_TRUST_MANAGER && manager instanceof X509ExtendedTrustManager) {
74 ((X509ExtendedTrustManager) manager).checkClientTrusted(peerCerts, authAlgorithm, engine);
75 } else {
76 manager.checkClientTrusted(peerCerts, authAlgorithm);
77 }
78 }
79 return BoringSSL.X509_V_OK;
80 } catch (Throwable cause) {
81 engineMap.remove(ssl);
82
83 if (cause instanceof OpenSslCertificateException) {
84
85
86 return ((OpenSslCertificateException) cause).errorCode();
87 }
88 if (cause instanceof CertificateExpiredException) {
89 return BoringSSL.X509_V_ERR_CERT_HAS_EXPIRED;
90 }
91 if (cause instanceof CertificateNotYetValidException) {
92 return BoringSSL.X509_V_ERR_CERT_NOT_YET_VALID;
93 }
94 return translateToError(cause);
95 }
96 }
97
98 private static int translateToError(Throwable cause) {
99 if (cause instanceof CertificateRevokedException) {
100 return BoringSSL.X509_V_ERR_CERT_REVOKED;
101 }
102
103
104
105
106 Throwable wrapped = cause.getCause();
107 while (wrapped != null) {
108 if (wrapped instanceof CertPathValidatorException) {
109 CertPathValidatorException ex = (CertPathValidatorException) wrapped;
110 CertPathValidatorException.Reason reason = ex.getReason();
111 if (reason == CertPathValidatorException.BasicReason.EXPIRED) {
112 return BoringSSL.X509_V_ERR_CERT_HAS_EXPIRED;
113 }
114 if (reason == CertPathValidatorException.BasicReason.NOT_YET_VALID) {
115 return BoringSSL.X509_V_ERR_CERT_NOT_YET_VALID;
116 }
117 if (reason == CertPathValidatorException.BasicReason.REVOKED) {
118 return BoringSSL.X509_V_ERR_CERT_REVOKED;
119 }
120 }
121 wrapped = wrapped.getCause();
122 }
123 return BoringSSL.X509_V_ERR_UNSPECIFIED;
124 }
125 }