Search in sources :

Example 1 with MemorySegment

use of jdk.incubator.foreign.MemorySegment in project tomcat by apache.

the class OpenSSLContext method openSSLCallbackAlpnSelectProto.

// int SSL_callback_alpn_select_proto(SSL* ssl, const unsigned char **out, unsigned char *outlen,
// const unsigned char *in, unsigned int inlen, void *arg)
public static int openSSLCallbackAlpnSelectProto(MemoryAddress ssl, MemoryAddress out, MemoryAddress outlen, MemoryAddress in, int inlen, MemoryAddress arg) {
    ContextState state = getState(arg);
    if (state == null) {
        log.warn(sm.getString("context.noSSL", Long.valueOf(arg.toRawLongValue())));
        return SSL_TLSEXT_ERR_NOACK();
    }
    // However, the Java 17 API forces use of a scope later on, so create one for everything
    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
        byte[] advertisedBytes = in.asSegment(inlen, scope).toByteArray();
        for (byte[] negotiableProtocolBytes : state.negotiableProtocols) {
            for (int i = 0; i <= advertisedBytes.length - negotiableProtocolBytes.length; i++) {
                if (advertisedBytes[i] == negotiableProtocolBytes[0]) {
                    for (int j = 0; j < negotiableProtocolBytes.length; j++) {
                        if (advertisedBytes[i + j] == negotiableProtocolBytes[j]) {
                            if (j == negotiableProtocolBytes.length - 1) {
                                MemorySegment outSegment = out.asSegment(CLinker.C_POINTER.byteSize(), scope);
                                MemorySegment outlenSegment = outlen.asSegment(CLinker.C_CHAR.byteSize(), scope);
                                // Match
                                MemoryAccess.setAddress(outSegment, in.addOffset(i));
                                MemoryAccess.setByte(outlenSegment, (byte) negotiableProtocolBytes.length);
                                return SSL_TLSEXT_ERR_OK();
                            }
                        } else {
                            break;
                        }
                    }
                }
            }
        }
        return SSL_TLSEXT_ERR_NOACK();
    }
}
Also used : ResourceScope(jdk.incubator.foreign.ResourceScope) AbstractEndpoint(org.apache.tomcat.util.net.AbstractEndpoint) MemorySegment(jdk.incubator.foreign.MemorySegment)

Example 2 with MemorySegment

use of jdk.incubator.foreign.MemorySegment in project tomcat by apache.

the class OpenSSLContext method addCertificate.

private void addCertificate(SSLHostConfigCertificate certificate) throws Exception {
    var allocator = SegmentAllocator.ofScope(state.contextScope);
    int index = getCertificateIndex(certificate);
    // Load Server key and certificate
    if (certificate.getCertificateFile() != null) {
        // Set certificate
        // SSLContext.setCertificate(state.ctx,
        // SSLHostConfig.adjustRelativePath(certificate.getCertificateFile()),
        // SSLHostConfig.adjustRelativePath(certificate.getCertificateKeyFile()),
        // certificate.getCertificateKeyPassword(), getCertificateIndex(certificate));
        var certificateFileNative = CLinker.toCString(SSLHostConfig.adjustRelativePath(certificate.getCertificateFile()), state.contextScope);
        var certificateKeyFileNative = (certificate.getCertificateKeyFile() == null) ? certificateFileNative : CLinker.toCString(SSLHostConfig.adjustRelativePath(certificate.getCertificateKeyFile()), state.contextScope);
        MemoryAddress bio;
        MemoryAddress cert = MemoryAddress.NULL;
        MemoryAddress key = MemoryAddress.NULL;
        if (certificate.getCertificateFile().endsWith(".pkcs12")) {
            // Load pkcs12
            bio = BIO_new(BIO_s_file());
            // (int)BIO_ctrl(b,BIO_C_SET_FILENAME, BIO_CLOSE|BIO_FP_READ,(char *)(name))
            if (BIO_ctrl(bio, BIO_C_SET_FILENAME(), BIO_CLOSE() | BIO_FP_READ(), certificateFileNative) <= 0) {
                BIO_free(bio);
                log.error(sm.getString("openssl.errorLoadingCertificate", "[0]:" + certificate.getCertificateFile()));
                return;
            }
            MemoryAddress p12 = d2i_PKCS12_bio(bio, MemoryAddress.NULL);
            BIO_free(bio);
            if (MemoryAddress.NULL.equals(p12)) {
                log.error(sm.getString("openssl.errorLoadingCertificate", "[1]:" + certificate.getCertificateFile()));
                return;
            }
            MemoryAddress passwordAddress = MemoryAddress.NULL;
            int passwordLength = 0;
            String callbackPassword = certificate.getCertificateKeyPassword();
            if (callbackPassword != null && callbackPassword.length() > 0) {
                MemorySegment password = CLinker.toCString(callbackPassword, state.contextScope);
                passwordAddress = password.address();
                passwordLength = (int) (password.byteSize() - 1);
            }
            if (PKCS12_verify_mac(p12, passwordAddress, passwordLength) <= 0) {
                // Bad password
                log.error(sm.getString("openssl.errorLoadingCertificate", "[2]:" + certificate.getCertificateFile()));
                PKCS12_free(p12);
                return;
            }
            MemorySegment certPointer = allocator.allocate(CLinker.C_POINTER);
            MemorySegment keyPointer = allocator.allocate(CLinker.C_POINTER);
            if (PKCS12_parse(p12, passwordAddress, keyPointer, certPointer, MemoryAddress.NULL) <= 0) {
                log.error(sm.getString("openssl.errorLoadingCertificate", "[3]:" + certificate.getCertificateFile()));
                PKCS12_free(p12);
                return;
            }
            PKCS12_free(p12);
            cert = MemoryAccess.getAddress(certPointer);
            key = MemoryAccess.getAddress(keyPointer);
        } else {
            // Load key
            bio = BIO_new(BIO_s_file());
            // (int)BIO_ctrl(b,BIO_C_SET_FILENAME, BIO_CLOSE|BIO_FP_READ,(char *)(name))
            if (BIO_ctrl(bio, BIO_C_SET_FILENAME(), BIO_CLOSE() | BIO_FP_READ(), certificateKeyFileNative) <= 0) {
                BIO_free(bio);
                log.error(sm.getString("openssl.errorLoadingCertificate", certificate.getCertificateKeyFile()));
                return;
            }
            key = MemoryAddress.NULL;
            for (int i = 0; i < 3; i++) {
                try {
                    callbackPasswordTheadLocal.set(certificate.getCertificateKeyPassword());
                    key = PEM_read_bio_PrivateKey(bio, MemoryAddress.NULL, openSSLCallbackPassword, MemoryAddress.NULL);
                } finally {
                    callbackPasswordTheadLocal.set(null);
                }
                if (!MemoryAddress.NULL.equals(key)) {
                    break;
                }
                BIO_ctrl(bio, BIO_CTRL_RESET(), 0, MemoryAddress.NULL);
            }
            BIO_free(bio);
            if (MemoryAddress.NULL.equals(key)) {
                if (!MemoryAddress.NULL.equals(OpenSSLLifecycleListener.enginePointer)) {
                    key = ENGINE_load_private_key(OpenSSLLifecycleListener.enginePointer, certificateKeyFileNative, MemoryAddress.NULL, MemoryAddress.NULL);
                }
            }
            if (MemoryAddress.NULL.equals(key)) {
                log.error(sm.getString("openssl.errorLoadingCertificate", certificate.getCertificateKeyFile()));
                return;
            }
            // Load certificate
            bio = BIO_new(BIO_s_file());
            if (BIO_ctrl(bio, BIO_C_SET_FILENAME(), BIO_CLOSE() | BIO_FP_READ(), certificateFileNative) <= 0) {
                BIO_free(bio);
                log.error(sm.getString("openssl.errorLoadingCertificate", certificate.getCertificateFile()));
                return;
            }
            try {
                callbackPasswordTheadLocal.set(certificate.getCertificateKeyPassword());
                cert = PEM_read_bio_X509_AUX(bio, MemoryAddress.NULL, openSSLCallbackPassword, MemoryAddress.NULL);
            } finally {
                callbackPasswordTheadLocal.set(null);
            }
            if (MemoryAddress.NULL.equals(cert) && /*int ERR_GET_REASON(unsigned long errcode) {
                         *    if (ERR_SYSTEM_ERROR(errcode))
                         *        return errcode & ERR_SYSTEM_MASK;
                         *    return errcode & ERR_REASON_MASK;
                         *}
                         *# define ERR_SYSTEM_ERROR(errcode)      (((errcode) & ERR_SYSTEM_FLAG) != 0)
                         *# define ERR_SYSTEM_FLAG                ((unsigned int)INT_MAX + 1)
                         *# define ERR_SYSTEM_MASK                ((unsigned int)INT_MAX)
                         *# define ERR_REASON_MASK                0X7FFFFF
                         */
            ((ERR_peek_last_error() & 0X7FFFFF) == PEM_R_NO_START_LINE())) {
                ERR_clear_error();
                BIO_ctrl(bio, BIO_CTRL_RESET(), 0, MemoryAddress.NULL);
                cert = d2i_X509_bio(bio, MemoryAddress.NULL);
            }
            BIO_free(bio);
            if (MemoryAddress.NULL.equals(cert)) {
                log.error(sm.getString("openssl.errorLoadingCertificate", certificate.getCertificateFile()));
                return;
            }
        }
        if (SSL_CTX_use_certificate(state.sslCtx, cert) <= 0) {
            logLastError(allocator, "openssl.errorLoadingCertificate");
            return;
        }
        if (SSL_CTX_use_PrivateKey(state.sslCtx, key) <= 0) {
            logLastError(allocator, "openssl.errorLoadingPrivateKey");
            return;
        }
        if (SSL_CTX_check_private_key(state.sslCtx) <= 0) {
            logLastError(allocator, "openssl.errorPrivateKeyCheck");
            return;
        }
        // Try to read DH parameters from the (first) SSLCertificateFile
        if (index == SSL_AIDX_RSA) {
            bio = BIO_new_file(certificateFileNative, CLinker.toCString("r", state.contextScope));
            var dh = PEM_read_bio_DHparams(bio, MemoryAddress.NULL, MemoryAddress.NULL, MemoryAddress.NULL);
            BIO_free(bio);
            // SSL_CTX_ctrl(sslCtx,SSL_CTRL_SET_TMP_DH,0,(char *)(dh))
            if (!MemoryAddress.NULL.equals(dh)) {
                SSL_CTX_ctrl(state.sslCtx, SSL_CTRL_SET_TMP_DH(), 0, dh);
                DH_free(dh);
            }
        }
        // Similarly, try to read the ECDH curve name from SSLCertificateFile...
        bio = BIO_new_file(certificateFileNative, CLinker.toCString("r", state.contextScope));
        var ecparams = PEM_read_bio_ECPKParameters(bio, MemoryAddress.NULL, MemoryAddress.NULL, MemoryAddress.NULL);
        BIO_free(bio);
        if (!MemoryAddress.NULL.equals(ecparams)) {
            int nid = EC_GROUP_get_curve_name(ecparams);
            var eckey = EC_KEY_new_by_curve_name(nid);
            // #  define SSL_CTX_set_tmp_ecdh(sslCtx,ecdh) \
            // SSL_CTX_ctrl(sslCtx,SSL_CTRL_SET_TMP_ECDH,0,(char *)(ecdh))
            SSL_CTX_ctrl(state.sslCtx, SSL_CTRL_SET_TMP_ECDH(), 0, eckey);
            EC_KEY_free(eckey);
            EC_GROUP_free(ecparams);
        }
        // Set callback for DH parameters
        MemoryAddress openSSLCallbackTmpDH = CLinker.getInstance().upcallStub(openSSLCallbackTmpDHHandle, openSSLCallbackTmpDHFunctionDescriptor, state.contextScope);
        SSL_CTX_set_tmp_dh_callback(state.sslCtx, openSSLCallbackTmpDH);
        // Set certificate chain file
        if (certificate.getCertificateChainFile() != null) {
            var certificateChainFileNative = CLinker.toCString(SSLHostConfig.adjustRelativePath(certificate.getCertificateChainFile()), state.contextScope);
            // SSLHostConfig.adjustRelativePath(certificate.getCertificateChainFile()), false);
            if (SSL_CTX_use_certificate_chain_file(state.sslCtx, certificateChainFileNative) <= 0) {
                log.error(sm.getString("openssl.errorLoadingCertificate", certificate.getCertificateChainFile()));
            }
        }
        // Set revocation
        // SSLContext.setCARevocation(state.ctx,
        // SSLHostConfig.adjustRelativePath(
        // sslHostConfig.getCertificateRevocationListFile()),
        // SSLHostConfig.adjustRelativePath(
        // sslHostConfig.getCertificateRevocationListPath()));
        MemoryAddress certificateStore = SSL_CTX_get_cert_store(state.sslCtx);
        if (sslHostConfig.getCertificateRevocationListFile() != null) {
            MemoryAddress x509Lookup = X509_STORE_add_lookup(certificateStore, X509_LOOKUP_file());
            var certificateRevocationListFileNative = CLinker.toCString(SSLHostConfig.adjustRelativePath(sslHostConfig.getCertificateRevocationListFile()), state.contextScope);
            // X509_LOOKUP_ctrl(lookup,X509_L_FILE_LOAD,file,type,NULL)
            if (X509_LOOKUP_ctrl(x509Lookup, X509_L_FILE_LOAD(), certificateRevocationListFileNative, X509_FILETYPE_PEM(), MemoryAddress.NULL) <= 0) {
                log.error(sm.getString("openssl.errorLoadingCertificateRevocationList", sslHostConfig.getCertificateRevocationListFile()));
            }
        }
        if (sslHostConfig.getCertificateRevocationListPath() != null) {
            MemoryAddress x509Lookup = X509_STORE_add_lookup(certificateStore, X509_LOOKUP_hash_dir());
            var certificateRevocationListPathNative = CLinker.toCString(SSLHostConfig.adjustRelativePath(sslHostConfig.getCertificateRevocationListPath()), state.contextScope);
            // X509_LOOKUP_ctrl(lookup,X509_L_ADD_DIR,path,type,NULL)
            if (X509_LOOKUP_ctrl(x509Lookup, X509_L_ADD_DIR(), certificateRevocationListPathNative, X509_FILETYPE_PEM(), MemoryAddress.NULL) <= 0) {
                log.error(sm.getString("openssl.errorLoadingCertificateRevocationList", sslHostConfig.getCertificateRevocationListPath()));
            }
        }
        X509_STORE_set_flags(certificateStore, X509_V_FLAG_CRL_CHECK() | X509_V_FLAG_CRL_CHECK_ALL());
    } else {
        String alias = certificate.getCertificateKeyAlias();
        X509KeyManager x509KeyManager = certificate.getCertificateKeyManager();
        if (alias == null) {
            alias = "tomcat";
        }
        X509Certificate[] chain = x509KeyManager.getCertificateChain(alias);
        if (chain == null) {
            alias = findAlias(x509KeyManager, certificate);
            chain = x509KeyManager.getCertificateChain(alias);
        }
        PrivateKey key = x509KeyManager.getPrivateKey(alias);
        StringBuilder sb = new StringBuilder(BEGIN_KEY);
        sb.append(Base64.getMimeEncoder(64, new byte[] { '\n' }).encodeToString(key.getEncoded()));
        sb.append(END_KEY);
        // SSLContext.setCertificateRaw(state.ctx, chain[0].getEncoded(),
        // sb.toString().getBytes(StandardCharsets.US_ASCII),
        // getCertificateIndex(certificate));
        var rawCertificate = allocator.allocateArray(CLinker.C_CHAR, chain[0].getEncoded());
        var rawCertificatePointer = allocator.allocate(CLinker.C_POINTER, rawCertificate);
        var rawKey = allocator.allocateArray(CLinker.C_CHAR, sb.toString().getBytes(StandardCharsets.US_ASCII));
        var x509cert = d2i_X509(MemoryAddress.NULL, rawCertificatePointer, rawCertificate.byteSize());
        if (MemoryAddress.NULL.equals(x509cert)) {
            logLastError(allocator, "openssl.errorLoadingCertificate");
            return;
        }
        var bio = BIO_new(BIO_s_mem());
        BIO_write(bio, rawKey.address(), (int) rawKey.byteSize());
        MemoryAddress privateKeyAddress = PEM_read_bio_PrivateKey(bio, MemoryAddress.NULL, MemoryAddress.NULL, MemoryAddress.NULL);
        BIO_free(bio);
        if (MemoryAddress.NULL.equals(privateKeyAddress)) {
            logLastError(allocator, "openssl.errorLoadingPrivateKey");
            return;
        }
        if (SSL_CTX_use_certificate(state.sslCtx, x509cert) <= 0) {
            logLastError(allocator, "openssl.errorLoadingCertificate");
            return;
        }
        if (SSL_CTX_use_PrivateKey(state.sslCtx, privateKeyAddress) <= 0) {
            logLastError(allocator, "openssl.errorLoadingPrivateKey");
            return;
        }
        if (SSL_CTX_check_private_key(state.sslCtx) <= 0) {
            logLastError(allocator, "openssl.errorPrivateKeyCheck");
            return;
        }
        // Set callback for DH parameters
        MemoryAddress openSSLCallbackTmpDH = CLinker.getInstance().upcallStub(openSSLCallbackTmpDHHandle, openSSLCallbackTmpDHFunctionDescriptor, state.contextScope);
        SSL_CTX_set_tmp_dh_callback(state.sslCtx, openSSLCallbackTmpDH);
        for (int i = 1; i < chain.length; i++) {
            // SSLContext.addChainCertificateRaw(state.ctx, chain[i].getEncoded());
            var rawCertificateChain = allocator.allocateArray(CLinker.C_CHAR, chain[i].getEncoded());
            var rawCertificateChainPointer = allocator.allocate(CLinker.C_POINTER, rawCertificateChain);
            var x509certChain = d2i_X509(MemoryAddress.NULL, rawCertificateChainPointer, rawCertificateChain.byteSize());
            if (MemoryAddress.NULL.equals(x509certChain)) {
                logLastError(allocator, "openssl.errorLoadingCertificate");
                return;
            }
            // # define SSL_CTX_add0_chain_cert(sslCtx,x509) SSL_CTX_ctrl(sslCtx,SSL_CTRL_CHAIN_CERT,0,(char *)(x509))
            if (SSL_CTX_ctrl(state.sslCtx, SSL_CTRL_CHAIN_CERT(), 0, x509certChain) <= 0) {
                logLastError(allocator, "openssl.errorAddingCertificate");
                return;
            }
        }
    }
}
Also used : PrivateKey(java.security.PrivateKey) X509KeyManager(javax.net.ssl.X509KeyManager) MemoryAddress(jdk.incubator.foreign.MemoryAddress) AbstractEndpoint(org.apache.tomcat.util.net.AbstractEndpoint) MemorySegment(jdk.incubator.foreign.MemorySegment) X509Certificate(java.security.cert.X509Certificate)

Example 3 with MemorySegment

use of jdk.incubator.foreign.MemorySegment in project tomcat by apache.

the class OpenSSLContext method openSSLCallbackPassword.

public static int openSSLCallbackPassword(MemoryAddress buf, int bufsiz, int verify, MemoryAddress cb) {
    if (log.isDebugEnabled()) {
        log.debug("Return password for certificate");
    }
    String callbackPassword = callbackPasswordTheadLocal.get();
    if (callbackPassword != null && callbackPassword.length() > 0) {
        try (var scope = ResourceScope.newConfinedScope()) {
            MemorySegment callbackPasswordNative = CLinker.toCString(callbackPassword, scope);
            if (callbackPasswordNative.byteSize() > bufsiz) {
                // The password is too long
                log.error(sm.getString("openssl.passwordTooLong"));
            } else {
                MemorySegment bufSegment = buf.asSegment(bufsiz, scope);
                bufSegment.copyFrom(callbackPasswordNative);
                return (int) callbackPasswordNative.byteSize();
            }
        }
    }
    return 0;
}
Also used : MemorySegment(jdk.incubator.foreign.MemorySegment)

Example 4 with MemorySegment

use of jdk.incubator.foreign.MemorySegment in project tomcat by apache.

the class OpenSSLContext method init.

/**
 * Setup the SSL_CTX.
 *
 * @param kms Must contain a KeyManager of the type
 *            {@code OpenSSLKeyManager}
 * @param tms Must contain a TrustManager of the type
 *            {@code X509TrustManager}
 * @param sr Is not used for this implementation.
 */
@Override
public synchronized void init(KeyManager[] kms, TrustManager[] tms, SecureRandom sr) {
    if (initialized) {
        log.warn(sm.getString("openssl.doubleInit"));
        return;
    }
    try {
        if (sslHostConfig.getInsecureRenegotiation()) {
            SSL_CTX_set_options(state.sslCtx, SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION());
        } else {
            SSL_CTX_clear_options(state.sslCtx, SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION());
        }
        // client's)
        if (sslHostConfig.getHonorCipherOrder()) {
            SSL_CTX_set_options(state.sslCtx, SSL_OP_CIPHER_SERVER_PREFERENCE());
        } else {
            SSL_CTX_clear_options(state.sslCtx, SSL_OP_CIPHER_SERVER_PREFERENCE());
        }
        // Disable compression if requested
        if (sslHostConfig.getDisableCompression()) {
            SSL_CTX_set_options(state.sslCtx, SSL_OP_NO_COMPRESSION());
        } else {
            SSL_CTX_clear_options(state.sslCtx, SSL_OP_NO_COMPRESSION());
        }
        // Disable TLS Session Tickets (RFC4507) to protect perfect forward secrecy
        if (sslHostConfig.getDisableSessionTickets()) {
            SSL_CTX_set_options(state.sslCtx, SSL_OP_NO_TICKET());
        } else {
            SSL_CTX_clear_options(state.sslCtx, SSL_OP_NO_TICKET());
        }
        // List the ciphers that the client is permitted to negotiate
        if (SSL_CTX_set_cipher_list(state.sslCtx, CLinker.toCString(sslHostConfig.getCiphers(), state.contextScope)) <= 0) {
            log.warn(sm.getString("engine.failedCipherSuite", sslHostConfig.getCiphers()));
        }
        if (certificate.getCertificateFile() == null) {
            certificate.setCertificateKeyManager(OpenSSLUtil.chooseKeyManager(kms));
        }
        addCertificate(certificate);
        // Client certificate verification
        int value = 0;
        switch(sslHostConfig.getCertificateVerification()) {
            case NONE:
                value = SSL_VERIFY_NONE();
                break;
            case OPTIONAL:
                value = SSL_VERIFY_PEER();
                break;
            case OPTIONAL_NO_CA:
                value = OPTIONAL_NO_CA;
                break;
            case REQUIRED:
                value = SSL_VERIFY_FAIL_IF_NO_PEER_CERT();
                break;
        }
        // SSLContext.setVerify(state.ctx, value, sslHostConfig.getCertificateVerificationDepth());
        if (SSL_CTX_set_default_verify_paths(state.sslCtx) > 0) {
            var store = SSL_CTX_get_cert_store(state.sslCtx);
            X509_STORE_set_flags(store, 0);
        }
        // Set int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) callback
        MemoryAddress openSSLCallbackVerify = CLinker.getInstance().upcallStub(openSSLCallbackVerifyHandle, openSSLCallbackVerifyFunctionDescriptor, state.contextScope);
        // Leave this just in case but in Tomcat this is always set again by the engine
        SSL_CTX_set_verify(state.sslCtx, value, openSSLCallbackVerify);
        // Trust and certificate verification
        var allocator = SegmentAllocator.ofScope(state.contextScope);
        if (tms != null) {
            // Client certificate verification based on custom trust managers
            state.x509TrustManager = chooseTrustManager(tms);
            MemoryAddress openSSLCallbackCertVerify = CLinker.getInstance().upcallStub(openSSLCallbackCertVerifyHandle, openSSLCallbackCertVerifyFunctionDescriptor, state.contextScope);
            SSL_CTX_set_cert_verify_callback(state.sslCtx, openSSLCallbackCertVerify, state.sslCtx);
            // an acceptable certificate
            for (X509Certificate caCert : state.x509TrustManager.getAcceptedIssuers()) {
                // SSLContext.addClientCACertificateRaw(state.ctx, caCert.getEncoded());
                var rawCACertificate = allocator.allocateArray(CLinker.C_CHAR, caCert.getEncoded());
                var rawCACertificatePointer = allocator.allocate(CLinker.C_POINTER, rawCACertificate);
                var x509CACert = d2i_X509(MemoryAddress.NULL, rawCACertificatePointer, rawCACertificate.byteSize());
                if (MemoryAddress.NULL.equals(x509CACert)) {
                    logLastError(allocator, "openssl.errorLoadingCertificate");
                } else if (SSL_CTX_add_client_CA(state.sslCtx, x509CACert) <= 0) {
                    logLastError(allocator, "openssl.errorAddingCertificate");
                } else if (log.isDebugEnabled()) {
                    log.debug(sm.getString("openssl.addedClientCaCert", caCert.toString()));
                }
            }
        } else {
            // Client certificate verification based on trusted CA files and dirs
            // SSLContext.setCACertificate(state.ctx,
            // SSLHostConfig.adjustRelativePath(sslHostConfig.getCaCertificateFile()),
            // SSLHostConfig.adjustRelativePath(sslHostConfig.getCaCertificatePath()));
            MemorySegment caCertificateFileNative = sslHostConfig.getCaCertificateFile() != null ? CLinker.toCString(SSLHostConfig.adjustRelativePath(sslHostConfig.getCaCertificateFile()), state.contextScope) : null;
            MemorySegment caCertificatePathNative = sslHostConfig.getCaCertificatePath() != null ? CLinker.toCString(SSLHostConfig.adjustRelativePath(sslHostConfig.getCaCertificatePath()), state.contextScope) : null;
            if (SSL_CTX_load_verify_locations(state.sslCtx, caCertificateFileNative == null ? MemoryAddress.NULL : caCertificateFileNative, caCertificatePathNative == null ? MemoryAddress.NULL : caCertificatePathNative) <= 0) {
                logLastError(allocator, "openssl.errorConfiguringLocations");
            } else {
                var caCerts = SSL_CTX_get_client_CA_list(state.sslCtx);
                if (MemoryAddress.NULL.equals(caCerts)) {
                    caCerts = SSL_load_client_CA_file(caCertificateFileNative);
                    if (!MemoryAddress.NULL.equals(caCerts)) {
                        SSL_CTX_set_client_CA_list(state.sslCtx, caCerts);
                    }
                } else {
                    if (SSL_add_file_cert_subjects_to_stack(caCerts, caCertificateFileNative) <= 0) {
                        caCerts = MemoryAddress.NULL;
                    }
                }
                if (MemoryAddress.NULL.equals(caCerts)) {
                    log.warn(sm.getString("openssl.noCACerts"));
                }
            }
        }
        if (state.negotiableProtocols != null && state.negotiableProtocols.size() > 0) {
            // int openSSLCallbackAlpnSelectProto(MemoryAddress ssl, MemoryAddress out, MemoryAddress outlen,
            // MemoryAddress in, int inlen, MemoryAddress arg
            MemoryAddress openSSLCallbackAlpnSelectProto = CLinker.getInstance().upcallStub(openSSLCallbackAlpnSelectProtoHandle, openSSLCallbackAlpnSelectProtoFunctionDescriptor, state.contextScope);
            SSL_CTX_set_alpn_select_cb(state.sslCtx, openSSLCallbackAlpnSelectProto, state.sslCtx);
        // Skip NPN (annoying and likely not useful anymore)
        // SSLContext.setNpnProtos(state.ctx, protocolsArray, SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE);
        }
        // Apply OpenSSLConfCmd if used
        OpenSSLConf openSslConf = sslHostConfig.getOpenSslConf();
        if (openSslConf != null && !MemoryAddress.NULL.equals(state.confCtx)) {
            // Check OpenSSLConfCmd if used
            if (log.isDebugEnabled()) {
                log.debug(sm.getString("openssl.checkConf"));
            }
            try {
                if (!checkConf(openSslConf)) {
                    log.error(sm.getString("openssl.errCheckConf"));
                    throw new Exception(sm.getString("openssl.errCheckConf"));
                }
            } catch (Exception e) {
                throw new Exception(sm.getString("openssl.errCheckConf"), e);
            }
            if (log.isDebugEnabled()) {
                log.debug(sm.getString("openssl.applyConf"));
            }
            try {
                if (!applyConf(openSslConf)) {
                    log.error(sm.getString("openssl.errApplyConf"));
                    throw new SSLException(sm.getString("openssl.errApplyConf"));
                }
            } catch (Exception e) {
                throw new SSLException(sm.getString("openssl.errApplyConf"), e);
            }
            // Reconfigure the enabled protocols
            long opts = SSL_CTX_get_options(state.sslCtx);
            List<String> enabled = new ArrayList<>();
            // Seems like there is no way to explicitly disable SSLv2Hello
            // in OpenSSL so it is always enabled
            enabled.add(Constants.SSL_PROTO_SSLv2Hello);
            if ((opts & SSL_OP_NO_TLSv1()) == 0) {
                enabled.add(Constants.SSL_PROTO_TLSv1);
            }
            if ((opts & SSL_OP_NO_TLSv1_1()) == 0) {
                enabled.add(Constants.SSL_PROTO_TLSv1_1);
            }
            if ((opts & SSL_OP_NO_TLSv1_2()) == 0) {
                enabled.add(Constants.SSL_PROTO_TLSv1_2);
            }
            if ((opts & SSL_OP_NO_TLSv1_3()) == 0) {
                enabled.add(Constants.SSL_PROTO_TLSv1_3);
            }
            if ((opts & SSL_OP_NO_SSLv2()) == 0) {
                enabled.add(Constants.SSL_PROTO_SSLv2);
            }
            if ((opts & SSL_OP_NO_SSLv3()) == 0) {
                enabled.add(Constants.SSL_PROTO_SSLv3);
            }
            sslHostConfig.setEnabledProtocols(enabled.toArray(new String[0]));
            // Reconfigure the enabled ciphers
            sslHostConfig.setEnabledCiphers(getCiphers(state.sslCtx));
        }
        sessionContext = new OpenSSLSessionContext(this);
        // If client authentication is being used, OpenSSL requires that
        // this is set so always set it in case an app is configured to
        // require it
        sessionContext.setSessionIdContext(DEFAULT_SESSION_ID_CONTEXT);
        sslHostConfig.setOpenSslContext(state.sslCtx.toRawLongValue());
        initialized = true;
    } catch (Exception e) {
        log.warn(sm.getString("openssl.errorSSLCtxInit"), e);
        destroy();
    }
}
Also used : ArrayList(java.util.ArrayList) OpenSSLConf(org.apache.tomcat.util.net.openssl.OpenSSLConf) SSLException(javax.net.ssl.SSLException) AbstractEndpoint(org.apache.tomcat.util.net.AbstractEndpoint) X509Certificate(java.security.cert.X509Certificate) MemorySegment(jdk.incubator.foreign.MemorySegment) CertificateException(java.security.cert.CertificateException) SSLException(javax.net.ssl.SSLException) MemoryAddress(jdk.incubator.foreign.MemoryAddress)

Example 5 with MemorySegment

use of jdk.incubator.foreign.MemorySegment in project tomcat by apache.

the class OpenSSLContext method openSSLCallbackCertVerify.

public static int openSSLCallbackCertVerify(MemoryAddress x509_ctx, MemoryAddress param) {
    if (log.isDebugEnabled()) {
        log.debug("Certificate verification");
    }
    if (MemoryAddress.NULL.equals(param)) {
        return 0;
    }
    ContextState state = getState(param);
    if (state == null) {
        log.warn(sm.getString("context.noSSL", Long.valueOf(param.toRawLongValue())));
        return 0;
    }
    MemoryAddress ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
    MemoryAddress /*STACK_OF(X509)*/
    sk = X509_STORE_CTX_get0_untrusted(x509_ctx);
    int len = OPENSSL_sk_num(sk);
    byte[][] certificateChain = new byte[len][];
    try (var scope = ResourceScope.newConfinedScope()) {
        var allocator = SegmentAllocator.ofScope(scope);
        for (int i = 0; i < len; i++) {
            MemoryAddress /*(X509*)*/
            x509 = OPENSSL_sk_value(sk, i);
            MemorySegment bufPointer = allocator.allocate(CLinker.C_POINTER, MemoryAddress.NULL);
            int length = i2d_X509(x509, bufPointer);
            if (length < 0) {
                certificateChain[i] = new byte[0];
                continue;
            }
            MemoryAddress buf = MemoryAccess.getAddress(bufPointer);
            certificateChain[i] = buf.asSegment(length, scope).toByteArray();
            // OPENSSL_free macro
            CRYPTO_free(buf, MemoryAddress.NULL, 0);
        }
        MemoryAddress cipher = SSL_get_current_cipher(ssl);
        String authMethod = (MemoryAddress.NULL.equals(cipher)) ? "UNKNOWN" : getCipherAuthenticationMethod(SSL_CIPHER_get_auth_nid(cipher), SSL_CIPHER_get_kx_nid(cipher));
        X509Certificate[] peerCerts = certificates(certificateChain);
        try {
            state.x509TrustManager.checkClientTrusted(peerCerts, authMethod);
            return 1;
        } catch (Exception e) {
            log.debug(sm.getString("openssl.certificateVerificationFailed"), e);
        }
    }
    return 0;
}
Also used : MemoryAddress(jdk.incubator.foreign.MemoryAddress) AbstractEndpoint(org.apache.tomcat.util.net.AbstractEndpoint) MemorySegment(jdk.incubator.foreign.MemorySegment) X509Certificate(java.security.cert.X509Certificate) CertificateException(java.security.cert.CertificateException) SSLException(javax.net.ssl.SSLException)

Aggregations

MemorySegment (jdk.incubator.foreign.MemorySegment)5 AbstractEndpoint (org.apache.tomcat.util.net.AbstractEndpoint)4 X509Certificate (java.security.cert.X509Certificate)3 MemoryAddress (jdk.incubator.foreign.MemoryAddress)3 CertificateException (java.security.cert.CertificateException)2 SSLException (javax.net.ssl.SSLException)2 PrivateKey (java.security.PrivateKey)1 ArrayList (java.util.ArrayList)1 X509KeyManager (javax.net.ssl.X509KeyManager)1 ResourceScope (jdk.incubator.foreign.ResourceScope)1 OpenSSLConf (org.apache.tomcat.util.net.openssl.OpenSSLConf)1