{"record":{"id":"3b53cc3c6c4f5f82","repo":"grpc/grpc-java","slug":"want-certificate-verification-but-got-null-or-empt","errorCode":null,"errorMessage":"Want certificate verification but got null or empty certificates","messagePattern":"Want certificate verification but got null or empty certificates","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"util/src/main/java/io/grpc/util/AdvancedTlsX509TrustManager.java","lineNumber":156,"sourceCode":"    // If found, use that as the delegate trust manager.\n    for (TrustManager tm : tms) {\n      if (tm instanceof X509ExtendedTrustManager) {\n        delegateManager = (X509ExtendedTrustManager) tm;\n        break;\n      }\n    }\n    if (delegateManager == null) {\n      throw new CertificateException(\n          \"Failed to find X509ExtendedTrustManager with default TrustManager algorithm \"\n              + TrustManagerFactory.getDefaultAlgorithm());\n    }\n    return delegateManager;\n  }\n\n  private void checkTrusted(X509Certificate[] chain, String authType, SSLEngine sslEngine,\n      Socket socket, boolean checkingServer) throws CertificateException {\n    if (chain == null || chain.length == 0) {\n      throw new IllegalArgumentException(\n          \"Want certificate verification but got null or empty certificates\");\n    }\n    if (sslEngine == null && socket == null) {\n      throw new CertificateException(NOT_ENOUGH_INFO_MESSAGE);\n    }\n    if (this.verification != Verification.INSECURELY_SKIP_ALL_VERIFICATION) {\n      X509ExtendedTrustManager currentDelegateManager = this.delegateManager;\n      if (currentDelegateManager == null) {\n        throw new CertificateException(\"No trust roots configured\");\n      }\n      if (checkingServer) {\n        String algorithm = this.verification == Verification.CERTIFICATE_AND_HOST_NAME_VERIFICATION\n            ? \"HTTPS\" : \"\";\n        if (sslEngine != null) {\n          SSLParameters sslParams = sslEngine.getSSLParameters();\n          sslParams.setEndpointIdentificationAlgorithm(algorithm);\n          sslEngine.setSSLParameters(sslParams);\n          currentDelegateManager.checkServerTrusted(chain, authType, sslEngine);","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/util/src/main/java/io/grpc/util/AdvancedTlsX509TrustManager.java#L138-L174","documentation":"checkTrusted validates the certificate chain only when it is non-null and non-empty; a null or empty chain is treated as a caller bug, not a certificate problem, so it throws IllegalArgumentException. If the caller intended to skip peer verification it should configure the manager accordingly rather than pass an empty chain.","triggerScenarios":"Calling checkClientTrusted or checkServerTrusted (any overload) with chain == null or chain.length == 0 — e.g., an upstream handshake passed no peer certificates, or a test harness passed an empty array.","commonSituations":"Tests constructing empty X509Certificate[] arrays; integration with an SSL layer that surfaced no peer certificates (anonymous cipher suites, misconfigured keystore); proxy termination stripping the peer chain; mistakenly calling verify with no certs fetched from a session.","solutions":["Pass a non-empty X509Certificate[] chain obtained from the peer (e.g., sslEngine.getSession().getPeerCertificates()).","If you intentionally want to skip verification, configure Verification.INSECURELY_SKIP_ALL_VERIFICATION via useInsecureSkipVerify() instead of passing an empty chain.","Check that the peer is actually presenting a certificate (client certs require setNeedClientAuth on server side).","Guard the call: only invoke checkTrusted paths when the session has peer certificates."],"exampleFix":"// before\ntrustManager.checkServerTrusted(new X509Certificate[0], \"TLS\", engine);\n\n// after\nX509Certificate[] chain = (X509Certificate[]) engine.getSession().getPeerCertificates();\nif (chain != null && chain.length > 0) {\n  trustManager.checkServerTrusted(chain, \"TLS\", engine);\n}","handlingStrategy":"validation","validationCode":"if (chain == null || chain.length == 0) {\n  throw new IllegalArgumentException(\"Peer presented no certificates; cannot verify\");\n}\ntrustManager.checkServerTrusted(chain, authType, sslEngine);","typeGuard":"static boolean hasCertificates(X509Certificate[] chain) {\n  return chain != null && chain.length > 0;\n}","tryCatchPattern":"try {\n  trustManager.checkServerTrusted(chain, authType, sslEngine);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"null or empty certificates\")) {\n    throw new CertificateException(\"Peer provided no certificate chain\", e);\n  }\n  throw e;\n}","preventionTips":["Obtain the chain from sslEngine.getSession().getPeerCertificates() and check it is non-empty before verifying.","Enable requireClientAuth/peer certificate demand so anonymous cipher suites (empty chains) are rejected at handshake.","If verification should be skipped, use useInsecureSkipVerify() rather than empty chains.","Guard against TLS-terminating proxies stripping the peer chain."],"tags":["tls","certificate","argument-validation","grpc"],"backgroundTag":"empty-required-field","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}