This commit is contained in:
2024-11-30 19:03:49 +08:00
commit 1e6763c160
3806 changed files with 737676 additions and 0 deletions

View File

@@ -0,0 +1,61 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
engine.ciphersFailure=Failed getting cipher list
engine.emptyCipherSuite=Empty cipher suite
engine.engineClosed=Engine is closed
engine.failedCipherSuite=Failed to enable cipher suite [{0}]
engine.inboundClose=Inbound closed before receiving peer's close_notify
engine.invalidBufferArray=offset: [{0}], length: [{1}] (expected: offset <= offset + length <= srcs.length [{2}])
engine.noSSLContext=No SSL context
engine.noSession=SSL session ID not available
engine.nullBuffer=Null buffer
engine.nullBufferInArray=Null buffer in array
engine.nullCipherSuite=Null cipher suite
engine.nullName=Null value name
engine.nullValue=Null value
engine.openSSLError=OpenSSL error: [{0}] message: [{1}]
engine.oversizedPacket=Encrypted packet is oversized
engine.unsupportedCipher=Unsupported cipher suite: [{0}] [{1}]
engine.unsupportedProtocol=Protocol [{0}] is not supported
engine.unverifiedPeer=Peer unverified
engine.writeToSSLFailed=Failed writing to SSL, returned: [{0}]
openssl.X509FactoryError=Error getting X509 factory instance
openssl.addedClientCaCert=Added client CA cert: [{0}]
openssl.applyConf=Applying OpenSSLConfCmd to SSL context
openssl.certificateVerificationFailed=Certificate verification failed
openssl.checkConf=Checking OpenSSLConf
openssl.doubleInit=SSL context already initialized, ignoring
openssl.errApplyConf=Could not apply OpenSSLConf to SSL context
openssl.errCheckConf=Error during OpenSSLConf check
openssl.errMakeConf=Could not create OpenSSLConf context
openssl.errorSSLCtxInit=Error initializing SSL context
openssl.keyManagerMissing=No key manager found
openssl.makeConf=Creating OpenSSLConf context
openssl.nonJsseCertficate=The certificate [{0}] or its private key [{1}] could not be processed using a JSSE key manager and will be given directly to OpenSSL
openssl.nonJsseChain=The certificate chain [{0}] was not specified or was not valid and JSSE requires a valid certificate chain so attempting to use OpenSSL directly
openssl.trustManagerMissing=No trust manager found
opensslconf.applyCommand=OpenSSLConf applying command (name [{0}], value [{1}])
opensslconf.applyFailed=Failure while applying OpenSSLConf to SSL context
opensslconf.checkCommand=OpenSSLConf checking command (name [{0}], value [{1}])
opensslconf.checkFailed=Failure while checking OpenSSLConf
opensslconf.failedCommand=OpenSSLConf failed command (name [{0}], value [{1}]) with result [{2}] - will be ignored
opensslconf.finishFailed=OpenSSLConf finish failed with result [{0}]
opensslconf.noCommandName=OpenSSLConf no command name - will be ignored (command value [{0}])
opensslconf.resultCommand=OpenSSLConf command (name [{0}], value [{1}]) returned [{2}]
sessionContext.nullTicketKeys=Null keys

View File

@@ -0,0 +1,33 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
engine.ciphersFailure=Fehler beim abfragen der Cipher Liste
engine.emptyCipherSuite=leere Cipher-Suite
engine.inboundClose=Die eingehende Verbindung wurde vor einer close_notify Nachricht der Gegenstelle geschlossen
engine.noSession=SSL Session-ID nicht vorhanden
engine.openSSLError=OpenSSL Fehler: [{0}] Nachricht: [{1}]
engine.unsupportedProtocol=Protokoll [{0}] ist nicht unterstützt
openssl.addedClientCaCert=Client CA Zertifikat hinzugefügt: [{0}]
openssl.certificateVerificationFailed=Zertifikatsprüfung fehlgeschlagen
openssl.errApplyConf=Die OpenSSLConf konnte nicht auf den SSL Context angewandt werden
openssl.errCheckConf=Fehler beim Prüfen der OpenSSLConf
openssl.errMakeConf=Der OpenSSLConf Context konnte nicht erzeugt werden
openssl.errorSSLCtxInit=Fehler beim initialisieren des SSL Contexts
openssl.keyManagerMissing=Kein Key-Manager gefunden
openssl.trustManagerMissing=Kein Trust-Manager gefunden
opensslconf.applyFailed=Fehler bei der Anwendung der OpenSSLConf auf den SSL Context
opensslconf.checkFailed=Fehler beim Prüfen der OpenSSLConf

View File

@@ -0,0 +1,25 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
engine.emptyCipherSuite=Suite de cifrado vacía
engine.engineClosed=El notor esta cerrado
engine.noSession=El identificador de la sesión SSL no está disponible
engine.openSSLError=Error de OpenSSL: [{0}] mensage: [{1}]\n
engine.writeToSSLFailed=Fallo al escribir hacia SSL, resultado: [{0}]
openssl.addedClientCaCert=Ceritifcado CA de cliente adicionado: [{0}]
openssl.trustManagerMissing=No se encontró un manejador confiable
opensslconf.checkFailed=Fallo mientras se chequeaba OpenSSLConf\n

View File

@@ -0,0 +1,61 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
engine.ciphersFailure=Echec en essayant d'obtenir la liste des chiffres
engine.emptyCipherSuite=La suite de chiffrement (cipher suite) est vide
engine.engineClosed=Le moteur a déjà été fermé
engine.failedCipherSuite=Impossible d''activer la suite de chiffres [{0}]
engine.inboundClose=L'entrée a été fermée avant d'avoir reçu le close_notify du pair
engine.invalidBufferArray=offset: [{0}], length: [{1}] (attendu: offset <= offset + length <= srcs.length [{2}])
engine.noSSLContext=Pas de contexte SSL
engine.noSession=Identificateur de session SSL non disponible
engine.nullBuffer=Tampon null
engine.nullBufferInArray=Tampon null dans le tableau
engine.nullCipherSuite=Suite de chiffres nulle
engine.nullName=La valeur du nom est null
engine.nullValue=La valeur est null
engine.openSSLError=Erreur OpenSSL : [{0}] message : [{1}]
engine.oversizedPacket=Le paquet crypté est trop gros
engine.unsupportedCipher=Suite de chiffres non supportée: [{0}] [{1}]
engine.unsupportedProtocol=Le protocole [{0}] n''est pas supporté
engine.unverifiedPeer=Le pair n'est pas vérifié
engine.writeToSSLFailed=Echec d''écriture vers SSL, code de retour: [{0}]
openssl.X509FactoryError=Impossible d'obtenir l'instance de la fabrique X509
openssl.addedClientCaCert=Ajout du certificat CA du client: [{0}]
openssl.applyConf=Application de OpenSSLConfCmd au contexte SSL
openssl.certificateVerificationFailed=La vérification du certificat a échoué
openssl.checkConf=Vérification de OpenSSLConf en cours
openssl.doubleInit=Le contexte SSL a déjà été initialisé, ignoré
openssl.errApplyConf=Impossible d'appliquer la OpenSSLConf au contexte SSL
openssl.errCheckConf=Erreur pendant la vérification de OpenSSLConf
openssl.errMakeConf=Impossible de créer le contexte de OpenSSLConf
openssl.errorSSLCtxInit=Erreur d'initialisation du contexte SSL
openssl.keyManagerMissing=Aucun gestionnaire de clés trouvé
openssl.makeConf=Création du contexte de OpenSSLConf
openssl.nonJsseCertficate=Le certificat [{0}] ou sa clé privée [{1}] n''a pas pu être traité en utilisant un gestionnaire de clé de JSSE, et sera directement passée à OpenSSL
openssl.nonJsseChain=La chaîne de certificat [{0}] n''a pas été spécifiée ou est invalide et JSSE requiert une chaîne de certificats valide, donc OpenSSL sera utilisé directement
openssl.trustManagerMissing=Gestionnaire de confiance non trouvé
opensslconf.applyCommand=Application de la commande OpenSSLConf (nom [{0}] valeur [{1}])
opensslconf.applyFailed=Erreur en appliquant OpenSSLConf au contexte SSL
opensslconf.checkCommand=Vérification de la commande OpenSSLConf (nom [{0}] valeur [{1}])
opensslconf.checkFailed=Echec de la vérification de OpenSSLConf
opensslconf.failedCommand=La commande OpenSSLConf (nom [{0}] valeur [{1}]) a échoué avec le résultat [{2}] qui sera ignoré
opensslconf.finishFailed=OpenSSLConf s''est terminé en échec avec le résultat [{0}]
opensslconf.noCommandName=Pas de nom de commande OpenSSLConf (valeur [{0}]), cela sera ignoré
opensslconf.resultCommand=La commande OpenSSLConf (nom [{0}] valeur [{1}]) a retourné [{2}]
sessionContext.nullTicketKeys=Clés nulles

View File

@@ -0,0 +1,59 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
engine.ciphersFailure=暗号リストを取得できません。
engine.emptyCipherSuite=暗号スイートがありません。
engine.engineClosed=エンジンが閉じられています
engine.failedCipherSuite=暗号スイート[{0}]を有効にできませんでした。
engine.inboundClose=ピアのclose_notifyを受信する前のインバウンドクローズ
engine.invalidBufferArray=オフセット: [{0}], 長さ: [{1}] (期待値: offset <= offset + length <= srcs.length [{2}])
engine.noSSLContext=SSLコンテキストがありません
engine.noSession=SSLセッションIDが利用可能ではありません
engine.nullBuffer=Null バッファ
engine.nullBufferInArray=配列内のNull バッファ
engine.nullCipherSuite=Null 暗号スイート
engine.nullName=Null値名
engine.nullValue=Null値
engine.openSSLError=OpenSSLエラー[{0}] メッセージ:[{1}]
engine.oversizedPacket=暗号化パケットのサイズが超過しています。
engine.unsupportedCipher=サポートされていない暗号スイート:[{0}] [{1}]
engine.unsupportedProtocol=プロトコル [{0}] には対応していません。
engine.unverifiedPeer=未確認のピア
engine.writeToSSLFailed=SSLへの書き込みに失敗しました。返却値[{0}]
openssl.X509FactoryError=X509ファクトリインスタンスの取得エラー
openssl.addedClientCaCert=クライアント CA 証明書を登録しました: [{0}]
openssl.applyConf=OpenSSLConfCmdをSSLコンテキストに適用します。
openssl.certificateVerificationFailed=証明書確認に失敗しました
openssl.checkConf=OpenSSLConfの確認
openssl.doubleInit=SSLコンテキストが既に初期化されています。無視します。
openssl.errApplyConf=OpenSSLConfをSSLコンテキストに適用できませんでした。
openssl.errCheckConf=OpenSSLConfチェック中のエラー
openssl.errMakeConf=OpenSSLConfコンテキストを作成できませんでした。
openssl.errorSSLCtxInit=SSL コンテキストの初期化中にエラーが発生しました。
openssl.keyManagerMissing=キーマネージャーが見つかりません。
openssl.makeConf=OpenSSLConfコンテキストの作成
openssl.trustManagerMissing=トラストマネージャが見つかりません
opensslconf.applyCommand=OpenSSLConfはコマンド名前[{0}]、値[{1}])を適用しています。
opensslconf.applyFailed=OpenSSLConfをSSLコンテキストに適用する際の失敗
opensslconf.checkCommand=OpenSSLConfチェックコマンド名前[{0}]、値[{1}]
opensslconf.checkFailed=OpenSSLConf のチェックが失敗しました。
opensslconf.failedCommand=結果[{2}]でOpenSSLConfがコマンド名前[{0}]、値[{1}])に失敗しました。無視されます。
opensslconf.finishFailed=結果[{0}]でOpenSSLConfのfinish処理が失敗しました
opensslconf.noCommandName=OpenSSLConfコマンド名なし - 無視されます(コマンド値[{0}]
opensslconf.resultCommand=OpenSSLConfコマンド名前[{0}]、値[{1}])が[{2}]を返しました。
sessionContext.nullTicketKeys=Null キー

View File

@@ -0,0 +1,61 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
engine.ciphersFailure=Cipher들의 목록을 얻지 못했습니다.
engine.emptyCipherSuite=CipherSuite 이름이 존재하지 않습니다.
engine.engineClosed=엔진이 닫혀 있습니다.
engine.failedCipherSuite=Cipher suite [{0}]을(를) 사용가능 상태로 설정하지 못했습니다.
engine.inboundClose=Peer의 close_notify를 받기 전에, Inbound가 닫혔습니다.
engine.invalidBufferArray=offset: [{0}], 길이: [{1}] (요구사항: offset <= offset + length <= srcs.length [{2}])
engine.noSSLContext=SSL 컨텍스트가 없음.
engine.noSession=SSL 세션 ID가 존재하지 않습니다.
engine.nullBuffer=널 버퍼
engine.nullBufferInArray=배열 내에 널 버퍼임
engine.nullCipherSuite=널 cipher suite
engine.nullName=name이 널입니다.
engine.nullValue=널 값
engine.openSSLError=OpenSSL 오류: [{0}], 메시지: [{1}]
engine.oversizedPacket=암호화된 패킷이 너무 큽니다.
engine.unsupportedCipher=지원되지 않는 cipher suite: [{0}] [{1}]
engine.unsupportedProtocol=프로토콜 [{0}]은(는) 지원되지 않습니다.
engine.unverifiedPeer=검증되지 않은 Peer
engine.writeToSSLFailed=SSL에 쓰기 실패, 반환 값: [{0}]
openssl.X509FactoryError=X509 팩토리 인스턴스를 얻는 중 오류 발생
openssl.addedClientCaCert=클라이언트 CA 인증서를 추가했습니다: [{0}]
openssl.applyConf=OpenSSLConfCmd를 SSL 컨텍스트에 적용합니다.
openssl.certificateVerificationFailed=인증서 검증에 실패했습니다.
openssl.checkConf=OpenSSLConf를 점검합니다.
openssl.doubleInit=SSL 컨텍스트가 이미 초기화되어 있으므로, 초기화 호출을 무시합니다.
openssl.errApplyConf=SSL 컨텍스트에 OpenSSLConf를 적용할 수 없었습니다.
openssl.errCheckConf=OpenSSLConf 점검 중 오류 발생
openssl.errMakeConf=OpenSSLConf 컨텍스트를 생성할 수 없었습니다.
openssl.errorSSLCtxInit=SSL 컨텍스트를 초기화 하는 중 오류 발생
openssl.keyManagerMissing=키 매니저를 찾을 수 없습니다.
openssl.makeConf=OpenSSLConf 컨텍스트를 생성합니다.
openssl.nonJsseCertficate=인증서 [{0}] 또는 그것의 개인 키 [{1}]이(가) JSSE 키 매니저를 사용하여 처리되지 못하였으므로, OpenSSL에 직접 전달할 것입니다.
openssl.nonJsseChain=해당 인증서 체인 [{0}]이(가) 지정되지 않았거나 유효하지 않으며, JSSE는 유효한 인증서 체인을 요구하므로, OpenSSL을 직접 사용하려 시도합니다.
openssl.trustManagerMissing=Trust 매니저를 찾을 수 없습니다.
opensslconf.applyCommand=OpenSSLConf이 명령을 적용합니다 (이름 [{0}], 값 [{1}]).
opensslconf.applyFailed=OpenSSLConf를 SSL 컨텍스트에 적용하는 중 실패
opensslconf.checkCommand=OpenSSLConf 점검 명령 (이름 [{0}], 값 [{1}])
opensslconf.checkFailed=OpenSSLConf 점검 실패
opensslconf.failedCommand=OpenSSLConf가 명령(이름: [{0}], 값: [{1}])을 처리하지 못했습니다 (결과: [{2}]). 이는 무시될 것입니다.
opensslconf.finishFailed=OpenSSLConf의 완료가 실패했습니다 (결과 값: [{0}]).
opensslconf.noCommandName=OpenSSLConf: 명령 이름이 없습니다 - 무시될 것입니다. (명령 값 [{0}])
opensslconf.resultCommand=OpenSSLConf 명령(이름: [{0}], 값: [{1}])이 [{2}]을(를) 반환했습니다.
sessionContext.nullTicketKeys=널 키들

View File

@@ -0,0 +1,16 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
engine.noSession=Идентификатор SSL сессии недоступен

View File

@@ -0,0 +1,35 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
engine.ciphersFailure=获取密码列表失败
engine.emptyCipherSuite=空密码套件
engine.engineClosed=引擎已经关闭
engine.noSession=SSL会话ID不可用
engine.nullCipherSuite=无加密套件
engine.openSSLError=OpenSSL 错误:[{0}] 信息: [{1}]
engine.unsupportedProtocol=不支持协议 [{0}]
engine.writeToSSLFailed=写入SSL失败返回[{0}]
openssl.X509FactoryError=获取X509工厂实例时出错
openssl.addedClientCaCert=添加了客户端 CA 证书:[{0}]
openssl.errApplyConf=无法将OpenSSLConf 应用于SSL 上下文
openssl.errMakeConf=无法创建OpenSSLConf上下文
openssl.keyManagerMissing=key管理器未找到
openssl.trustManagerMissing=没有找到.信任管理者
opensslconf.checkFailed=检查OpenSSLConf时失败。
opensslconf.finishFailed=OpenSSLConf 配置失败结果为 [{0}]
sessionContext.nullTicketKeys=Null keys

View File

@@ -0,0 +1,128 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.util.net.openssl;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.jni.SSLConf;
import org.apache.tomcat.util.res.StringManager;
public class OpenSSLConf implements Serializable {
private static final long serialVersionUID = 1L;
private static final Log log = LogFactory.getLog(OpenSSLConf.class);
private static final StringManager sm = StringManager.getManager(OpenSSLConf.class);
private final List<OpenSSLConfCmd> commands = new ArrayList<>();
public void addCmd(OpenSSLConfCmd cmd) {
commands.add(cmd);
}
public List<OpenSSLConfCmd> getCommands() {
return commands;
}
public boolean check(long cctx) throws Exception {
boolean result = true;
OpenSSLConfCmd cmd;
String name;
String value;
int rc;
for (int i = 0; i < commands.size(); i++) {
cmd = commands.get(i);
name = cmd.getName();
value = cmd.getValue();
if (name == null) {
log.error(sm.getString("opensslconf.noCommandName", value));
result = false;
continue;
}
if (log.isDebugEnabled()) {
log.debug(sm.getString("opensslconf.checkCommand", name, value));
}
try {
rc = SSLConf.check(cctx, name, value);
} catch (Exception e) {
log.error(sm.getString("opensslconf.checkFailed"));
return false;
}
if (rc <= 0) {
log.error(sm.getString("opensslconf.failedCommand", name, value,
Integer.toString(rc)));
result = false;
} else if (log.isDebugEnabled()) {
log.debug(sm.getString("opensslconf.resultCommand", name, value,
Integer.toString(rc)));
}
}
if (!result) {
log.error(sm.getString("opensslconf.checkFailed"));
}
return result;
}
public boolean apply(long cctx, long ctx) throws Exception {
boolean result = true;
SSLConf.assign(cctx, ctx);
OpenSSLConfCmd cmd;
String name;
String value;
int rc;
for (int i = 0; i < commands.size(); i++) {
cmd = commands.get(i);
name = cmd.getName();
value = cmd.getValue();
if (name == null) {
log.error(sm.getString("opensslconf.noCommandName", value));
result = false;
continue;
}
if (log.isDebugEnabled()) {
log.debug(sm.getString("opensslconf.applyCommand", name, value));
}
try {
rc = SSLConf.apply(cctx, name, value);
} catch (Exception e) {
log.error(sm.getString("opensslconf.applyFailed"));
return false;
}
if (rc <= 0) {
log.error(sm.getString("opensslconf.failedCommand", name, value,
Integer.toString(rc)));
result = false;
} else if (log.isDebugEnabled()) {
log.debug(sm.getString("opensslconf.resultCommand", name, value,
Integer.toString(rc)));
}
}
rc = SSLConf.finish(cctx);
if (rc <= 0) {
log.error(sm.getString("opensslconf.finishFailed", Integer.toString(rc)));
result = false;
}
if (!result) {
log.error(sm.getString("opensslconf.applyFailed"));
}
return result;
}
}

View File

@@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.util.net.openssl;
import java.io.Serializable;
public class OpenSSLConfCmd implements Serializable {
private static final long serialVersionUID = 1L;
private String name = null;
private String value = null;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

View File

@@ -0,0 +1,563 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.util.net.openssl;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.jni.CertificateVerifier;
import org.apache.tomcat.jni.Pool;
import org.apache.tomcat.jni.SSL;
import org.apache.tomcat.jni.SSLConf;
import org.apache.tomcat.jni.SSLContext;
import org.apache.tomcat.util.codec.binary.Base64;
import org.apache.tomcat.util.net.AbstractEndpoint;
import org.apache.tomcat.util.net.Constants;
import org.apache.tomcat.util.net.SSLHostConfig;
import org.apache.tomcat.util.net.SSLHostConfig.CertificateVerification;
import org.apache.tomcat.util.net.SSLHostConfigCertificate;
import org.apache.tomcat.util.net.SSLHostConfigCertificate.Type;
import org.apache.tomcat.util.res.StringManager;
public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
private static final Base64 BASE64_ENCODER = new Base64(64, new byte[] {'\n'});
private static final Log log = LogFactory.getLog(OpenSSLContext.class);
// Note: this uses the main "net" package strings as many are common with APR
private static final StringManager netSm = StringManager.getManager(AbstractEndpoint.class);
private static final StringManager sm = StringManager.getManager(OpenSSLContext.class);
private static final String defaultProtocol = "TLS";
private final SSLHostConfig sslHostConfig;
private final SSLHostConfigCertificate certificate;
private OpenSSLSessionContext sessionContext;
private X509TrustManager x509TrustManager;
private final List<String> negotiableProtocols;
private String enabledProtocol;
public String getEnabledProtocol() {
return enabledProtocol;
}
public void setEnabledProtocol(String protocol) {
enabledProtocol = (protocol == null) ? defaultProtocol : protocol;
}
private final long aprPool;
private final AtomicInteger aprPoolDestroyed = new AtomicInteger(0);
// OpenSSLConfCmd context
protected final long cctx;
// SSL context
protected final long ctx;
static final CertificateFactory X509_CERT_FACTORY;
private static final String BEGIN_KEY = "-----BEGIN PRIVATE KEY-----\n";
private static final Object END_KEY = "\n-----END PRIVATE KEY-----";
private boolean initialized = false;
static {
try {
X509_CERT_FACTORY = CertificateFactory.getInstance("X.509");
} catch (CertificateException e) {
throw new IllegalStateException(sm.getString("openssl.X509FactoryError"), e);
}
}
public OpenSSLContext(SSLHostConfigCertificate certificate, List<String> negotiableProtocols)
throws SSLException {
this.sslHostConfig = certificate.getSSLHostConfig();
this.certificate = certificate;
aprPool = Pool.create(0);
boolean success = false;
try {
// Create OpenSSLConfCmd context if used
OpenSSLConf openSslConf = sslHostConfig.getOpenSslConf();
if (openSslConf != null) {
try {
if (log.isDebugEnabled())
log.debug(sm.getString("openssl.makeConf"));
cctx = SSLConf.make(aprPool,
SSL.SSL_CONF_FLAG_FILE |
SSL.SSL_CONF_FLAG_SERVER |
SSL.SSL_CONF_FLAG_CERTIFICATE |
SSL.SSL_CONF_FLAG_SHOW_ERRORS);
} catch (Exception e) {
throw new SSLException(sm.getString("openssl.errMakeConf"), e);
}
} else {
cctx = 0;
}
sslHostConfig.setOpenSslConfContext(Long.valueOf(cctx));
// SSL protocol
int value = SSL.SSL_PROTOCOL_NONE;
for (String protocol : sslHostConfig.getEnabledProtocols()) {
if (Constants.SSL_PROTO_SSLv2Hello.equalsIgnoreCase(protocol)) {
// NO-OP. OpenSSL always supports SSLv2Hello
} else if (Constants.SSL_PROTO_SSLv2.equalsIgnoreCase(protocol)) {
value |= SSL.SSL_PROTOCOL_SSLV2;
} else if (Constants.SSL_PROTO_SSLv3.equalsIgnoreCase(protocol)) {
value |= SSL.SSL_PROTOCOL_SSLV3;
} else if (Constants.SSL_PROTO_TLSv1.equalsIgnoreCase(protocol)) {
value |= SSL.SSL_PROTOCOL_TLSV1;
} else if (Constants.SSL_PROTO_TLSv1_1.equalsIgnoreCase(protocol)) {
value |= SSL.SSL_PROTOCOL_TLSV1_1;
} else if (Constants.SSL_PROTO_TLSv1_2.equalsIgnoreCase(protocol)) {
value |= SSL.SSL_PROTOCOL_TLSV1_2;
} else if (Constants.SSL_PROTO_TLSv1_3.equalsIgnoreCase(protocol)) {
value |= SSL.SSL_PROTOCOL_TLSV1_3;
} else if (Constants.SSL_PROTO_ALL.equalsIgnoreCase(protocol)) {
value |= SSL.SSL_PROTOCOL_ALL;
} else {
// Should not happen since filtering to build
// enabled protocols removes invalid values.
throw new Exception(netSm.getString(
"endpoint.apr.invalidSslProtocol", protocol));
}
}
// Create SSL Context
try {
ctx = SSLContext.make(aprPool, value, SSL.SSL_MODE_SERVER);
} catch (Exception e) {
// If the sslEngine is disabled on the AprLifecycleListener
// there will be an Exception here but there is no way to check
// the AprLifecycleListener settings from here
throw new Exception(
netSm.getString("endpoint.apr.failSslContextMake"), e);
}
this.negotiableProtocols = negotiableProtocols;
success = true;
} catch(Exception e) {
throw new SSLException(sm.getString("openssl.errorSSLCtxInit"), e);
} finally {
if (!success) {
destroy();
}
}
}
@Override
public synchronized void destroy() {
// Guard against multiple destroyPools() calls triggered by construction exception and finalize() later
if (aprPoolDestroyed.compareAndSet(0, 1)) {
if (ctx != 0) {
SSLContext.free(ctx);
}
if (cctx != 0) {
SSLConf.free(cctx);
}
if (aprPool != 0) {
Pool.destroy(aprPool);
}
}
}
/**
* 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()) {
SSLContext.setOptions(ctx, SSL.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
} else {
SSLContext.clearOptions(ctx, SSL.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
}
// Use server's preference order for ciphers (rather than
// client's)
String honorCipherOrderStr = sslHostConfig.getHonorCipherOrder();
if (honorCipherOrderStr != null) {
if (Boolean.parseBoolean(honorCipherOrderStr)) {
SSLContext.setOptions(ctx, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
} else {
SSLContext.clearOptions(ctx, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
}
}
// Disable compression if requested
if (sslHostConfig.getDisableCompression()) {
SSLContext.setOptions(ctx, SSL.SSL_OP_NO_COMPRESSION);
} else {
SSLContext.clearOptions(ctx, SSL.SSL_OP_NO_COMPRESSION);
}
// Disable TLS Session Tickets (RFC4507) to protect perfect forward secrecy
if (sslHostConfig.getDisableSessionTickets()) {
SSLContext.setOptions(ctx, SSL.SSL_OP_NO_TICKET);
} else {
SSLContext.clearOptions(ctx, SSL.SSL_OP_NO_TICKET);
}
// List the ciphers that the client is permitted to negotiate
SSLContext.setCipherSuite(ctx, 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.SSL_CVERIFY_NONE;
break;
case OPTIONAL:
value = SSL.SSL_CVERIFY_OPTIONAL;
break;
case OPTIONAL_NO_CA:
value = SSL.SSL_CVERIFY_OPTIONAL_NO_CA;
break;
case REQUIRED:
value = SSL.SSL_CVERIFY_REQUIRE;
break;
}
SSLContext.setVerify(ctx, value, sslHostConfig.getCertificateVerificationDepth());
if (tms != null) {
// Client certificate verification based on custom trust managers
x509TrustManager = chooseTrustManager(tms);
SSLContext.setCertVerifyCallback(ctx, new CertificateVerifier() {
@Override
public boolean verify(long ssl, byte[][] chain, String auth) {
X509Certificate[] peerCerts = certificates(chain);
try {
x509TrustManager.checkClientTrusted(peerCerts, auth);
return true;
} catch (Exception e) {
log.debug(sm.getString("openssl.certificateVerificationFailed"), e);
}
return false;
}
});
// Pass along the DER encoded certificates of the accepted client
// certificate issuers, so that their subjects can be presented
// by the server during the handshake to allow the client choosing
// an acceptable certificate
for (X509Certificate caCert : x509TrustManager.getAcceptedIssuers()) {
SSLContext.addClientCACertificateRaw(ctx, caCert.getEncoded());
if (log.isDebugEnabled())
log.debug(sm.getString("openssl.addedClientCaCert", caCert.toString()));
}
} else {
// Client certificate verification based on trusted CA files and dirs
SSLContext.setCACertificate(ctx,
SSLHostConfig.adjustRelativePath(sslHostConfig.getCaCertificateFile()),
SSLHostConfig.adjustRelativePath(sslHostConfig.getCaCertificatePath()));
}
if (negotiableProtocols != null && negotiableProtocols.size() > 0) {
List<String> protocols = new ArrayList<>();
protocols.addAll(negotiableProtocols);
protocols.add("http/1.1");
String[] protocolsArray = protocols.toArray(new String[0]);
SSLContext.setAlpnProtos(ctx, protocolsArray, SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE);
SSLContext.setNpnProtos(ctx, protocolsArray, SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE);
}
// Apply OpenSSLConfCmd if used
OpenSSLConf openSslConf = sslHostConfig.getOpenSslConf();
if (openSslConf != null && cctx != 0) {
// Check OpenSSLConfCmd if used
if (log.isDebugEnabled())
log.debug(sm.getString("openssl.checkConf"));
try {
if (!openSslConf.check(cctx)) {
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 (!openSslConf.apply(cctx, ctx)) {
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
int opts = SSLContext.getOptions(ctx);
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.SSL_OP_NO_TLSv1) == 0) {
enabled.add(Constants.SSL_PROTO_TLSv1);
}
if ((opts & SSL.SSL_OP_NO_TLSv1_1) == 0) {
enabled.add(Constants.SSL_PROTO_TLSv1_1);
}
if ((opts & SSL.SSL_OP_NO_TLSv1_2) == 0) {
enabled.add(Constants.SSL_PROTO_TLSv1_2);
}
if ((opts & SSL.SSL_OP_NO_SSLv2) == 0) {
enabled.add(Constants.SSL_PROTO_SSLv2);
}
if ((opts & SSL.SSL_OP_NO_SSLv3) == 0) {
enabled.add(Constants.SSL_PROTO_SSLv3);
}
sslHostConfig.setEnabledProtocols(
enabled.toArray(new String[enabled.size()]));
// Reconfigure the enabled ciphers
sslHostConfig.setEnabledCiphers(SSLContext.getCiphers(ctx));
}
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(SSLContext.DEFAULT_SESSION_ID_CONTEXT);
sslHostConfig.setOpenSslContext(Long.valueOf(ctx));
initialized = true;
} catch (Exception e) {
log.warn(sm.getString("openssl.errorSSLCtxInit"), e);
destroy();
}
}
public void addCertificate(SSLHostConfigCertificate certificate) throws Exception {
// Load Server key and certificate
if (certificate.getCertificateFile() != null) {
// Set certificate
SSLContext.setCertificate(ctx,
SSLHostConfig.adjustRelativePath(certificate.getCertificateFile()),
SSLHostConfig.adjustRelativePath(certificate.getCertificateKeyFile()),
certificate.getCertificateKeyPassword(), getCertificateIndex(certificate));
// Set certificate chain file
SSLContext.setCertificateChainFile(ctx,
SSLHostConfig.adjustRelativePath(certificate.getCertificateChainFile()), false);
// Set revocation
SSLContext.setCARevocation(ctx,
SSLHostConfig.adjustRelativePath(
sslHostConfig.getCertificateRevocationListFile()),
SSLHostConfig.adjustRelativePath(
sslHostConfig.getCertificateRevocationListPath()));
} 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);
String encoded = BASE64_ENCODER.encodeToString(key.getEncoded());
if (encoded.endsWith("\n")) {
encoded = encoded.substring(0, encoded.length() - 1);
}
sb.append(encoded);
sb.append(END_KEY);
SSLContext.setCertificateRaw(ctx, chain[0].getEncoded(),
sb.toString().getBytes(StandardCharsets.US_ASCII),
getCertificateIndex(certificate));
for (int i = 1; i < chain.length; i++) {
SSLContext.addChainCertificateRaw(ctx, chain[i].getEncoded());
}
}
}
private static int getCertificateIndex(SSLHostConfigCertificate certificate) {
int result;
// If the type is undefined there will only be one certificate (enforced
// in SSLHostConfig) so use the RSA slot.
if (certificate.getType() == Type.RSA || certificate.getType() == Type.UNDEFINED) {
result = SSL.SSL_AIDX_RSA;
} else if (certificate.getType() == Type.EC) {
result = SSL.SSL_AIDX_ECC;
} else if (certificate.getType() == Type.DSA) {
result = SSL.SSL_AIDX_DSA;
} else {
result = SSL.SSL_AIDX_MAX;
}
return result;
}
/*
* Find a valid alias when none was specified in the config.
*/
private static String findAlias(X509KeyManager keyManager,
SSLHostConfigCertificate certificate) {
Type type = certificate.getType();
String result = null;
List<Type> candidateTypes = new ArrayList<>();
if (Type.UNDEFINED.equals(type)) {
// Try all types to find an suitable alias
candidateTypes.addAll(Arrays.asList(Type.values()));
candidateTypes.remove(Type.UNDEFINED);
} else {
// Look for the specific type to find a suitable alias
candidateTypes.add(type);
}
Iterator<Type> iter = candidateTypes.iterator();
while (result == null && iter.hasNext()) {
result = keyManager.chooseServerAlias(iter.next().toString(), null, null);
}
return result;
}
private static X509TrustManager chooseTrustManager(TrustManager[] managers) {
for (TrustManager m : managers) {
if (m instanceof X509TrustManager) {
return (X509TrustManager) m;
}
}
throw new IllegalStateException(sm.getString("openssl.trustManagerMissing"));
}
private static X509Certificate[] certificates(byte[][] chain) {
X509Certificate[] peerCerts = new X509Certificate[chain.length];
for (int i = 0; i < peerCerts.length; i++) {
peerCerts[i] = new OpenSSLX509Certificate(chain[i]);
}
return peerCerts;
}
long getSSLContextID() {
return ctx;
}
@Override
public SSLSessionContext getServerSessionContext() {
return sessionContext;
}
@Override
public SSLEngine createSSLEngine() {
return new OpenSSLEngine(ctx, defaultProtocol, false, sessionContext,
(negotiableProtocols != null && negotiableProtocols.size() > 0), initialized,
sslHostConfig.getCertificateVerificationDepth(),
sslHostConfig.getCertificateVerification() == CertificateVerification.OPTIONAL_NO_CA);
}
@Override
public SSLServerSocketFactory getServerSocketFactory() {
throw new UnsupportedOperationException();
}
@Override
public SSLParameters getSupportedSSLParameters() {
throw new UnsupportedOperationException();
}
@Override
public X509Certificate[] getCertificateChain(String alias) {
X509Certificate[] chain = null;
X509KeyManager x509KeyManager = certificate.getCertificateKeyManager();
if (x509KeyManager != null) {
if (alias == null) {
alias = "tomcat";
}
chain = x509KeyManager.getCertificateChain(alias);
if (chain == null) {
alias = findAlias(x509KeyManager, certificate);
chain = x509KeyManager.getCertificateChain(alias);
}
}
return chain;
}
@Override
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] acceptedCerts = null;
if (x509TrustManager != null) {
acceptedCerts = x509TrustManager.getAcceptedIssuers();
}
return acceptedCerts;
}
@Override
protected void finalize() throws Throwable {
/*
* When an SSLHostConfig is replaced at runtime, it is not possible to
* call destroy() on the associated OpenSSLContext since it is likely
* that there will be in-progress connections using the OpenSSLContext.
* A reference chain has been deliberately established (see
* OpenSSLSessionContext) to ensure that the OpenSSLContext remains
* ineligible for GC while those connections are alive. Once those
* connections complete, the OpenSSLContext will become eligible for GC
* and this method will ensure that the associated native resources are
* cleaned up.
*/
try {
destroy();
} finally {
super.finalize();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,44 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.util.net.openssl;
import javax.net.ssl.SSLSession;
import org.apache.tomcat.util.net.SSLHostConfigCertificate;
import org.apache.tomcat.util.net.SSLImplementation;
import org.apache.tomcat.util.net.SSLSupport;
import org.apache.tomcat.util.net.SSLUtil;
import org.apache.tomcat.util.net.jsse.JSSESupport;
public class OpenSSLImplementation extends SSLImplementation {
@Override
public SSLSupport getSSLSupport(SSLSession session) {
return new JSSESupport(session);
}
@Override
public SSLUtil getSSLUtil(SSLHostConfigCertificate certificate) {
return new OpenSSLUtil(certificate);
}
@Override
public boolean isAlpnSupported() {
// OpenSSL supported ALPN
return true;
}
}

View File

@@ -0,0 +1,148 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.util.net.openssl;
import java.util.Enumeration;
import java.util.NoSuchElementException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSessionContext;
import org.apache.tomcat.jni.SSL;
import org.apache.tomcat.jni.SSLContext;
import org.apache.tomcat.util.res.StringManager;
/**
* OpenSSL specific {@link SSLSessionContext} implementation.
*/
public class OpenSSLSessionContext implements SSLSessionContext {
private static final StringManager sm = StringManager.getManager(OpenSSLSessionContext.class);
private static final Enumeration<byte[]> EMPTY = new EmptyEnumeration();
private final OpenSSLSessionStats stats;
// This is deliberately unused. The reference is retained so that a
// reference chain is established and maintained to the OpenSSLContext while
// there is a connection that is using the OpenSSLContext. Therefore, the
// OpenSSLContext can not be eligible for GC while it is in use.
@SuppressWarnings("unused")
private final OpenSSLContext context;
private final long contextID;
OpenSSLSessionContext(OpenSSLContext context) {
this.context = context;
this.contextID = context.getSSLContextID();
stats = new OpenSSLSessionStats(contextID);
}
@Override
public SSLSession getSession(byte[] bytes) {
return null;
}
@Override
public Enumeration<byte[]> getIds() {
return EMPTY;
}
/**
* Sets the SSL session ticket keys of this context.
*
* @param keys The session ticket keys
*/
public void setTicketKeys(byte[] keys) {
if (keys == null) {
throw new IllegalArgumentException(sm.getString("sessionContext.nullTicketKeys"));
}
SSLContext.setSessionTicketKeys(contextID, keys);
}
/**
* Enable or disable caching of SSL sessions.
*
* @param enabled {@code true} to enable caching, {@code false} to disable
*/
public void setSessionCacheEnabled(boolean enabled) {
long mode = enabled ? SSL.SSL_SESS_CACHE_SERVER : SSL.SSL_SESS_CACHE_OFF;
SSLContext.setSessionCacheMode(contextID, mode);
}
/**
* @return {@code true} if caching of SSL sessions is enabled, {@code false}
* otherwise.
*/
public boolean isSessionCacheEnabled() {
return SSLContext.getSessionCacheMode(contextID) == SSL.SSL_SESS_CACHE_SERVER;
}
/**
* @return The statistics for this context.
*/
public OpenSSLSessionStats stats() {
return stats;
}
@Override
public void setSessionTimeout(int seconds) {
if (seconds < 0) {
throw new IllegalArgumentException();
}
SSLContext.setSessionCacheTimeout(contextID, seconds);
}
@Override
public int getSessionTimeout() {
return (int) SSLContext.getSessionCacheTimeout(contextID);
}
@Override
public void setSessionCacheSize(int size) {
if (size < 0) {
throw new IllegalArgumentException();
}
SSLContext.setSessionCacheSize(contextID, size);
}
@Override
public int getSessionCacheSize() {
return (int) SSLContext.getSessionCacheSize(contextID);
}
/**
* Set the context within which session be reused (server side only)
* See <a href="http://www.openssl.org/docs/ssl/SSL_CTX_set_session_id_context.html">
* man SSL_CTX_set_session_id_context</a>
*
* @param sidCtx can be any kind of binary data, it is therefore possible to use e.g. the name
* of the application and/or the hostname and/or service name
* @return {@code true} if success, {@code false} otherwise.
*/
public boolean setSessionIdContext(byte[] sidCtx) {
return SSLContext.setSessionIdContext(contextID, sidCtx);
}
private static final class EmptyEnumeration implements Enumeration<byte[]> {
@Override
public boolean hasMoreElements() {
return false;
}
@Override
public byte[] nextElement() {
throw new NoSuchElementException();
}
}
}

View File

@@ -0,0 +1,126 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.util.net.openssl;
import org.apache.tomcat.jni.SSLContext;
/**
* Stats exposed by an OpenSSL session context.
*
* @see <a href="https://www.openssl.org/docs/ssl/SSL_CTX_sess_number.html"><code>SSL_CTX_sess_number</code></a>
*/
public final class OpenSSLSessionStats {
private final long context;
OpenSSLSessionStats(long context) {
this.context = context;
}
/**
* @return The current number of sessions in the internal session cache.
*/
public long number() {
return SSLContext.sessionNumber(context);
}
/**
* @return The number of started SSL/TLS handshakes in client mode.
*/
public long connect() {
return SSLContext.sessionConnect(context);
}
/**
* @return The number of successfully established SSL/TLS sessions in client mode.
*/
public long connectGood() {
return SSLContext.sessionConnectGood(context);
}
/**
* @return The number of start renegotiations in client mode.
*/
public long connectRenegotiate() {
return SSLContext.sessionConnectRenegotiate(context);
}
/**
* @return The number of started SSL/TLS handshakes in server mode.
*/
public long accept() {
return SSLContext.sessionAccept(context);
}
/**
* @return The number of successfully established SSL/TLS sessions in server mode.
*/
public long acceptGood() {
return SSLContext.sessionAcceptGood(context);
}
/**
* @return The number of start renegotiations in server mode.
*/
public long acceptRenegotiate() {
return SSLContext.sessionAcceptRenegotiate(context);
}
/**
* @return The number of successfully reused sessions. In client mode, a
* session set with {@code SSL_set_session} successfully reused is
* counted as a hit. In server mode, a session successfully
* retrieved from internal or external cache is counted as a hit.
*/
public long hits() {
return SSLContext.sessionHits(context);
}
/**
* @return The number of successfully retrieved sessions from the external
* session cache in server mode.
*/
public long cbHits() {
return SSLContext.sessionCbHits(context);
}
/**
* @return The number of sessions proposed by clients that were not found in
* the internal session cache in server mode.
*/
public long misses() {
return SSLContext.sessionMisses(context);
}
/**
* @return The number of sessions proposed by clients and either found in
* the internal or external session cache in server mode, but that
* were invalid due to timeout. These sessions are not included in
* the {@link #hits()} count.
*/
public long timeouts() {
return SSLContext.sessionTimeouts(context);
}
/**
* @return The number of sessions that were removed because the maximum
* session cache size was exceeded.
*/
public long cacheFull() {
return SSLContext.sessionCacheFull(context);
}
}

View File

@@ -0,0 +1,128 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.util.net.openssl;
import java.io.IOException;
import java.security.KeyStoreException;
import java.util.List;
import java.util.Set;
import javax.net.ssl.KeyManager;
import javax.net.ssl.X509KeyManager;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.net.SSLContext;
import org.apache.tomcat.util.net.SSLHostConfigCertificate;
import org.apache.tomcat.util.net.SSLUtilBase;
import org.apache.tomcat.util.net.jsse.JSSEKeyManager;
import org.apache.tomcat.util.res.StringManager;
public class OpenSSLUtil extends SSLUtilBase {
private static final Log log = LogFactory.getLog(OpenSSLUtil.class);
private static final StringManager sm = StringManager.getManager(OpenSSLContext.class);
public OpenSSLUtil(SSLHostConfigCertificate certificate) {
super(certificate);
}
@Override
protected Log getLog() {
return log;
}
@Override
protected Set<String> getImplementedProtocols() {
return OpenSSLEngine.IMPLEMENTED_PROTOCOLS_SET;
}
@Override
protected Set<String> getImplementedCiphers() {
return OpenSSLEngine.AVAILABLE_CIPHER_SUITES;
}
@Override
protected boolean isTls13RenegAuthAvailable() {
// OpenSSL does support authentication after the initial handshake
return true;
}
@Override
public SSLContext createSSLContextInternal(List<String> negotiableProtocols) throws Exception {
return new OpenSSLContext(certificate, negotiableProtocols);
}
public static X509KeyManager chooseKeyManager(KeyManager[] managers) throws Exception {
if (managers == null) {
return null;
}
for (KeyManager manager : managers) {
if (manager instanceof JSSEKeyManager) {
return (JSSEKeyManager) manager;
}
}
for (KeyManager manager : managers) {
if (manager instanceof X509KeyManager) {
return (X509KeyManager) manager;
}
}
throw new IllegalStateException(sm.getString("openssl.keyManagerMissing"));
}
@Override
public KeyManager[] getKeyManagers() throws Exception {
try {
return super.getKeyManagers();
} catch (IllegalArgumentException e) {
// No (or invalid?) certificate chain was provided for the cert
String msg = sm.getString("openssl.nonJsseChain", certificate.getCertificateChainFile());
if (log.isDebugEnabled()) {
log.info(msg, e);
} else {
log.info(msg);
}
return null;
} catch (KeyStoreException | IOException e) {
// Depending on what is presented, JSSE may also throw
// KeyStoreException or IOException if it doesn't understand the
// provided file.
if (certificate.getCertificateFile() != null) {
String msg = sm.getString("openssl.nonJsseCertficate",
certificate.getCertificateFile(), certificate.getCertificateKeyFile());
if (log.isDebugEnabled()) {
log.info(msg, e);
} else {
log.info(msg);
}
// Assume JSSE processing of the certificate failed, try again with OpenSSL
// without a key manager
return null;
}
throw e;
}
}
}

View File

@@ -0,0 +1,190 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.util.net.openssl;
import java.io.ByteArrayInputStream;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Principal;
import java.security.PublicKey;
import java.security.SignatureException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.Set;
final class OpenSSLX509Certificate extends X509Certificate {
private final byte[] bytes;
private X509Certificate wrapped;
public OpenSSLX509Certificate(byte[] bytes) {
this.bytes = bytes;
}
@Override
public void checkValidity() throws CertificateExpiredException, CertificateNotYetValidException {
unwrap().checkValidity();
}
@Override
public void checkValidity(Date date) throws CertificateExpiredException, CertificateNotYetValidException {
unwrap().checkValidity(date);
}
@Override
public int getVersion() {
return unwrap().getVersion();
}
@Override
public BigInteger getSerialNumber() {
return unwrap().getSerialNumber();
}
@Override
public Principal getIssuerDN() {
return unwrap().getIssuerDN();
}
@Override
public Principal getSubjectDN() {
return unwrap().getSubjectDN();
}
@Override
public Date getNotBefore() {
return unwrap().getNotBefore();
}
@Override
public Date getNotAfter() {
return unwrap().getNotAfter();
}
@Override
public byte[] getTBSCertificate() throws CertificateEncodingException {
return unwrap().getTBSCertificate();
}
@Override
public byte[] getSignature() {
return unwrap().getSignature();
}
@Override
public String getSigAlgName() {
return unwrap().getSigAlgName();
}
@Override
public String getSigAlgOID() {
return unwrap().getSigAlgOID();
}
@Override
public byte[] getSigAlgParams() {
return unwrap().getSigAlgParams();
}
@Override
public boolean[] getIssuerUniqueID() {
return unwrap().getIssuerUniqueID();
}
@Override
public boolean[] getSubjectUniqueID() {
return unwrap().getSubjectUniqueID();
}
@Override
public boolean[] getKeyUsage() {
return unwrap().getKeyUsage();
}
@Override
public int getBasicConstraints() {
return unwrap().getBasicConstraints();
}
@Override
public byte[] getEncoded() {
return bytes.clone();
}
@Override
public void verify(PublicKey key)
throws CertificateException, NoSuchAlgorithmException,
InvalidKeyException, NoSuchProviderException, SignatureException {
unwrap().verify(key);
}
@Override
public void verify(PublicKey key, String sigProvider)
throws CertificateException, NoSuchAlgorithmException, InvalidKeyException,
NoSuchProviderException, SignatureException {
unwrap().verify(key, sigProvider);
}
@Override
public String toString() {
return unwrap().toString();
}
@Override
public PublicKey getPublicKey() {
return unwrap().getPublicKey();
}
@Override
public boolean hasUnsupportedCriticalExtension() {
return unwrap().hasUnsupportedCriticalExtension();
}
@Override
public Set<String> getCriticalExtensionOIDs() {
return unwrap().getCriticalExtensionOIDs();
}
@Override
public Set<String> getNonCriticalExtensionOIDs() {
return unwrap().getNonCriticalExtensionOIDs();
}
@Override
public byte[] getExtensionValue(String oid) {
return unwrap().getExtensionValue(oid);
}
private X509Certificate unwrap() {
X509Certificate wrapped = this.wrapped;
if (wrapped == null) {
try {
wrapped = this.wrapped = (X509Certificate) OpenSSLContext.X509_CERT_FACTORY.generateCertificate(
new ByteArrayInputStream(bytes));
} catch (CertificateException e) {
throw new IllegalStateException(e);
}
}
return wrapped;
}
}

View File

@@ -0,0 +1,34 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.util.net.openssl.ciphers;
public enum Authentication {
RSA /* RSA auth */,
DSS /* DSS auth */,
aNULL /* no auth (i.e. use ADH or AECDH) */,
DH /* Fixed DH auth (kDHd or kDHr) */,
ECDH /* Fixed ECDH auth (kECDHe or kECDHr) */,
KRB5 /* KRB5 auth */,
ECDSA /* ECDSA auth*/,
PSK /* PSK auth */,
GOST94 /* GOST R 34.10-94 signature auth */,
GOST01 /* GOST R 34.10-2001 */,
FZA /* Fortezza */,
SRP,
ANY /* TLS 1.3 */
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.util.net.openssl.ciphers;
enum Encryption {
AES128,
AES128CCM,
AES128CCM8,
AES128GCM,
AES256,
AES256CCM,
AES256CCM8,
AES256GCM,
ARIA128GCM,
ARIA256GCM,
CAMELLIA256,
CAMELLIA128,
CHACHA20POLY1305,
TRIPLE_DES,
DES,
IDEA,
eGOST2814789CNT,
SEED,
FZA,
RC4,
RC2,
eNULL
}

View File

@@ -0,0 +1,28 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.util.net.openssl.ciphers;
enum EncryptionLevel {
STRONG_NONE,
EXP40,
EXP56,
LOW,
MEDIUM,
HIGH,
FIPS
}

View File

@@ -0,0 +1,37 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.util.net.openssl.ciphers;
enum KeyExchange {
EECDH /* SSL_kEECDH - ephemeral ECDH */,
RSA /* SSL_kRSA - RSA key exchange */,
DHr /* SSL_kDHr - DH cert, RSA CA cert */ /* no such ciphersuites supported! */,
DHd /* SSL_kDHd - DH cert, DSA CA cert */ /* no such ciphersuite supported! */,
EDH /* SSL_kDHE - tmp DH key no DH cert */,
PSK /* SSK_kPSK - PSK */,
FZA /* SSL_kFZA - Fortezza */ /* no such ciphersuite supported! */,
KRB5 /* SSL_kKRB5 - Kerberos 5 key exchange */,
ECDHr /* SSL_kECDHr - ECDH cert, RSA CA cert */,
ECDHe /* SSL_kECDHe - ECDH cert, ECDSA CA cert */,
GOST /* SSL_kGOST - GOST key exchange */,
SRP /* SSL_kSRP - SRP */,
RSAPSK,
ECDHEPSK,
DHEPSK,
ANY /* TLS 1.3 */
}

View File

@@ -0,0 +1,16 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
converter.mapping=Cipher suite mapping: [{0}] => [{1}]

View File

@@ -0,0 +1,16 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
converter.mapping=Association de la suite de chiffres: [{0}] => [{1}]

View File

@@ -0,0 +1,16 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
converter.mapping=暗号スイートの対応付け: [{0}] => [{1}]

View File

@@ -0,0 +1,16 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
converter.mapping=Cipher suite 매핑: [{0}] => [{1}]

View File

@@ -0,0 +1,28 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.util.net.openssl.ciphers;
enum MessageDigest {
MD5,
SHA1,
GOST94,
GOST89MAC,
SHA256,
SHA384,
AEAD
}

View File

@@ -0,0 +1,915 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.util.net.openssl.ciphers;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.net.Constants;
import org.apache.tomcat.util.res.StringManager;
/**
* Class in charge with parsing openSSL expressions to define a list of ciphers.
*/
public class OpenSSLCipherConfigurationParser {
private static final Log log = LogFactory.getLog(OpenSSLCipherConfigurationParser.class);
private static final StringManager sm =
StringManager.getManager("org.apache.tomcat.util.net.jsse.res");
private static boolean initialized = false;
private static final String SEPARATOR = ":|,| ";
/**
* If ! is used then the ciphers are permanently deleted from the list. The ciphers deleted can never reappear in the list
* even if they are explicitly stated.
*/
private static final String EXCLUDE = "!";
/**
* If - is used then the ciphers are deleted from the list, but some or all of the ciphers can be added again by later
* options.
*/
private static final String DELETE = "-";
/**
* If + is used then the ciphers are moved to the end of the list. This option doesn't add any new ciphers it just moves
* matching existing ones.
*/
private static final String TO_END = "+";
/**
* Lists of cipher suites can be combined in a single cipher string using the + character.
* This is used as a logical and operation.
* For example SHA1+DES represents all cipher suites containing the SHA1 and the DES algorithms.
*/
private static final String AND = "+";
/**
* All ciphers by their openssl alias name.
*/
private static final Map<String, List<Cipher>> aliases = new LinkedHashMap<>();
/**
* the 'NULL' ciphers that is those offering no encryption. Because these offer no encryption at all and are a security risk
* they are disabled unless explicitly included.
*/
private static final String eNULL = "eNULL";
/**
* The cipher suites offering no authentication. This is currently the anonymous DH algorithms. T These cipher suites are
* vulnerable to a 'man in the middle' attack and so their use is normally discouraged.
*/
private static final String aNULL = "aNULL";
/**
* 'high' encryption cipher suites. This currently means those with key lengths larger than 128 bits, and some cipher suites
* with 128-bit keys.
*/
private static final String HIGH = "HIGH";
/**
* 'medium' encryption cipher suites, currently some of those using 128 bit encryption.
*/
private static final String MEDIUM = "MEDIUM";
/**
* 'low' encryption cipher suites, currently those using 64 or 56 bit encryption algorithms but excluding export cipher
* suites.
*/
private static final String LOW = "LOW";
/**
* Export encryption algorithms. Including 40 and 56 bits algorithms.
*/
private static final String EXPORT = "EXPORT";
/**
* 40 bit export encryption algorithms.
*/
private static final String EXPORT40 = "EXPORT40";
/**
* 56 bit export encryption algorithms.
*/
private static final String EXPORT56 = "EXPORT56";
/**
* Cipher suites using RSA key exchange.
*/
private static final String kRSA = "kRSA";
/**
* Cipher suites using RSA authentication.
*/
private static final String aRSA = "aRSA";
/**
* Cipher suites using RSA for key exchange
* Despite what the docs say, RSA is equivalent to kRSA.
*/
private static final String RSA = "RSA";
/**
* Cipher suites using ephemeral DH key agreement.
*/
private static final String kEDH = "kEDH";
/**
* Cipher suites using ephemeral DH key agreement.
*/
private static final String kDHE = "kDHE";
/**
* Cipher suites using ephemeral DH key agreement. equivalent to kEDH:-ADH
*/
private static final String EDH = "EDH";
/**
* Cipher suites using ephemeral DH key agreement. equivalent to kEDH:-ADH
*/
private static final String DHE = "DHE";
/**
* Cipher suites using DH key agreement and DH certificates signed by CAs with RSA keys.
*/
private static final String kDHr = "kDHr";
/**
* Cipher suites using DH key agreement and DH certificates signed by CAs with DSS keys.
*/
private static final String kDHd = "kDHd";
/**
* Cipher suites using DH key agreement and DH certificates signed by CAs with RSA or DSS keys.
*/
private static final String kDH = "kDH";
/**
* Cipher suites using fixed ECDH key agreement signed by CAs with RSA keys.
*/
private static final String kECDHr = "kECDHr";
/**
* Cipher suites using fixed ECDH key agreement signed by CAs with ECDSA keys.
*/
private static final String kECDHe = "kECDHe";
/**
* Cipher suites using fixed ECDH key agreement signed by CAs with RSA and ECDSA keys or either respectively.
*/
private static final String kECDH = "kECDH";
/**
* Cipher suites using ephemeral ECDH key agreement, including anonymous cipher suites.
*/
private static final String kEECDH = "kEECDH";
/**
* Cipher suites using ephemeral ECDH key agreement, excluding anonymous cipher suites.
* Same as "kEECDH:-AECDH"
*/
private static final String EECDH = "EECDH";
/**
* Cipher suitesusing ECDH key exchange, including anonymous, ephemeral and fixed ECDH.
*/
private static final String ECDH = "ECDH";
/**
* Cipher suites using ephemeral ECDH key agreement, including anonymous cipher suites.
*/
private static final String kECDHE = "kECDHE";
/**
* Cipher suites using authenticated ephemeral ECDH key agreement
*/
private static final String ECDHE = "ECDHE";
/**
* Cipher suites using authenticated ephemeral ECDH key agreement
*/
private static final String EECDHE = "EECDHE";
/**
* Anonymous Elliptic Curve Diffie Hellman cipher suites.
*/
private static final String AECDH = "AECDH";
/**
* Cipher suites using DSS for key exchange
*/
private static final String DSS = "DSS";
/**
* Cipher suites using DSS authentication, i.e. the certificates carry DSS keys.
*/
private static final String aDSS = "aDSS";
/**
* Cipher suites effectively using DH authentication, i.e. the certificates carry DH keys.
*/
private static final String aDH = "aDH";
/**
* Cipher suites effectively using ECDH authentication, i.e. the certificates carry ECDH keys.
*/
private static final String aECDH = "aECDH";
/**
* Cipher suites effectively using ECDSA authentication, i.e. the certificates carry ECDSA keys.
*/
private static final String aECDSA = "aECDSA";
/**
* Cipher suites effectively using ECDSA authentication, i.e. the certificates carry ECDSA keys.
*/
private static final String ECDSA = "ECDSA";
/**
* Ciphers suites using FORTEZZA key exchange algorithms.
*/
private static final String kFZA = "kFZA";
/**
* Ciphers suites using FORTEZZA authentication algorithms.
*/
private static final String aFZA = "aFZA";
/**
* Ciphers suites using FORTEZZA encryption algorithms.
*/
private static final String eFZA = "eFZA";
/**
* Ciphers suites using all FORTEZZA algorithms.
*/
private static final String FZA = "FZA";
/**
* Cipher suites using DH, including anonymous DH, ephemeral DH and fixed DH.
*/
private static final String DH = "DH";
/**
* Anonymous DH cipher suites.
*/
private static final String ADH = "ADH";
/**
* Cipher suites using 128 bit AES.
*/
private static final String AES128 = "AES128";
/**
* Cipher suites using 256 bit AES.
*/
private static final String AES256 = "AES256";
/**
* Cipher suites using either 128 or 256 bit AES.
*/
private static final String AES = "AES";
/**
* AES in Galois Counter Mode (GCM): these cipher suites are only supported in TLS v1.2.
*/
private static final String AESGCM = "AESGCM";
/**
* AES in Counter with CBC-MAC Mode (CCM).
*/
private static final String AESCCM = "AESCCM";
/**
* AES in Counter with CBC-MAC Mode and 8-byte authentication (CCM8).
*/
private static final String AESCCM8 = "AESCCM8";
/**
* Cipher suites using either 128 bit ARIA.
*/
private static final String ARIA128 = "ARIA128";
/**
* Cipher suites using either 256 bit ARIA.
*/
private static final String ARIA256 = "ARIA256";
/**
* Cipher suites using either 128 or 256 bit ARIA.
*/
private static final String ARIA = "ARIA";
/**
* Cipher suites using 128 bit CAMELLIA.
*/
private static final String CAMELLIA128 = "CAMELLIA128";
/**
* Cipher suites using 256 bit CAMELLIA.
*/
private static final String CAMELLIA256 = "CAMELLIA256";
/**
* Cipher suites using either 128 or 256 bit CAMELLIA.
*/
private static final String CAMELLIA = "CAMELLIA";
/**
* Cipher suites using CHACHA20.
*/
private static final String CHACHA20 = "CHACHA20";
/**
* Cipher suites using triple DES.
*/
private static final String TRIPLE_DES = "3DES";
/**
* Cipher suites using DES (not triple DES).
*/
private static final String DES = "DES";
/**
* Cipher suites using RC4.
*/
private static final String RC4 = "RC4";
/**
* Cipher suites using RC2.
*/
private static final String RC2 = "RC2";
/**
* Cipher suites using IDEA.
*/
private static final String IDEA = "IDEA";
/**
* Cipher suites using SEED.
*/
private static final String SEED = "SEED";
/**
* Cipher suites using MD5.
*/
private static final String MD5 = "MD5";
/**
* Cipher suites using SHA1.
*/
private static final String SHA1 = "SHA1";
/**
* Cipher suites using SHA1.
*/
private static final String SHA = "SHA";
/**
* Cipher suites using SHA256.
*/
private static final String SHA256 = "SHA256";
/**
* Cipher suites using SHA384.
*/
private static final String SHA384 = "SHA384";
/**
* Cipher suites using KRB5.
*/
private static final String KRB5 = "KRB5";
/**
* Cipher suites using GOST R 34.10 (either 2001 or 94) for authentication.
*/
private static final String aGOST = "aGOST";
/**
* Cipher suites using GOST R 34.10-2001 for authentication.
*/
private static final String aGOST01 = "aGOST01";
/**
* Cipher suites using GOST R 34.10-94 authentication (note that R 34.10-94 standard has been expired so use GOST R
* 34.10-2001)
*/
private static final String aGOST94 = "aGOST94";
/**
* Cipher suites using using VKO 34.10 key exchange, specified in the RFC 4357.
*/
private static final String kGOST = "kGOST";
/**
* Cipher suites, using HMAC based on GOST R 34.11-94.
*/
private static final String GOST94 = "GOST94";
/**
* Cipher suites using GOST 28147-89 MAC instead of HMAC.
*/
private static final String GOST89MAC = "GOST89MAC";
/**
* Cipher suites using SRP authentication, specified in the RFC 5054.
*/
private static final String aSRP = "aSRP";
/**
* Cipher suites using SRP key exchange, specified in the RFC 5054.
*/
private static final String kSRP = "kSRP";
/**
* Same as kSRP
*/
private static final String SRP = "SRP";
/**
* Cipher suites using pre-shared keys (PSK).
*/
private static final String PSK = "PSK";
/**
* Cipher suites using PSK authentication.
*/
private static final String aPSK = "aPSK";
/**
* Cipher suites using PSK key 'exchange'.
*/
private static final String kPSK = "kPSK";
private static final String kRSAPSK = "kRSAPSK";
private static final String kECDHEPSK = "kECDHEPSK";
private static final String kDHEPSK = "kDHEPSK";
private static final String DEFAULT = "DEFAULT";
private static final String COMPLEMENTOFDEFAULT = "COMPLEMENTOFDEFAULT";
private static final String ALL = "ALL";
private static final String COMPLEMENTOFALL = "COMPLEMENTOFALL";
private static final Map<String,String> jsseToOpenSSL = new HashMap<>();
private static final void init() {
for (Cipher cipher : Cipher.values()) {
String alias = cipher.getOpenSSLAlias();
if (aliases.containsKey(alias)) {
aliases.get(alias).add(cipher);
} else {
List<Cipher> list = new ArrayList<>();
list.add(cipher);
aliases.put(alias, list);
}
aliases.put(cipher.name(), Collections.singletonList(cipher));
for (String openSSlAltName : cipher.getOpenSSLAltNames()) {
if (aliases.containsKey(openSSlAltName)) {
aliases.get(openSSlAltName).add(cipher);
} else {
List<Cipher> list = new ArrayList<>();
list.add(cipher);
aliases.put(openSSlAltName, list);
}
}
jsseToOpenSSL.put(cipher.name(), cipher.getOpenSSLAlias());
Set<String> jsseNames = cipher.getJsseNames();
for (String jsseName : jsseNames) {
jsseToOpenSSL.put(jsseName, cipher.getOpenSSLAlias());
}
}
List<Cipher> allCiphersList = Arrays.asList(Cipher.values());
Collections.reverse(allCiphersList);
LinkedHashSet<Cipher> allCiphers = defaultSort(new LinkedHashSet<>(allCiphersList));
addListAlias(eNULL, filterByEncryption(allCiphers, Collections.singleton(Encryption.eNULL)));
LinkedHashSet<Cipher> all = new LinkedHashSet<>(allCiphers);
remove(all, eNULL);
addListAlias(ALL, all);
addListAlias(HIGH, filterByEncryptionLevel(allCiphers, Collections.singleton(EncryptionLevel.HIGH)));
addListAlias(MEDIUM, filterByEncryptionLevel(allCiphers, Collections.singleton(EncryptionLevel.MEDIUM)));
addListAlias(LOW, filterByEncryptionLevel(allCiphers, Collections.singleton(EncryptionLevel.LOW)));
addListAlias(EXPORT, filterByEncryptionLevel(allCiphers, new HashSet<>(Arrays.asList(EncryptionLevel.EXP40, EncryptionLevel.EXP56))));
aliases.put("EXP", aliases.get(EXPORT));
addListAlias(EXPORT40, filterByEncryptionLevel(allCiphers, Collections.singleton(EncryptionLevel.EXP40)));
addListAlias(EXPORT56, filterByEncryptionLevel(allCiphers, Collections.singleton(EncryptionLevel.EXP56)));
aliases.put("NULL", aliases.get(eNULL));
aliases.put(COMPLEMENTOFALL, aliases.get(eNULL));
addListAlias(aNULL, filterByAuthentication(allCiphers, Collections.singleton(Authentication.aNULL)));
addListAlias(kRSA, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.RSA)));
addListAlias(aRSA, filterByAuthentication(allCiphers, Collections.singleton(Authentication.RSA)));
// Despite what the docs say, RSA is equivalent to kRSA
aliases.put(RSA, aliases.get(kRSA));
addListAlias(kEDH, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.EDH)));
addListAlias(kDHE, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.EDH)));
Set<Cipher> edh = filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.EDH));
edh.removeAll(filterByAuthentication(allCiphers, Collections.singleton(Authentication.aNULL)));
addListAlias(EDH, edh);
addListAlias(DHE, edh);
addListAlias(kDHr, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.DHr)));
addListAlias(kDHd, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.DHd)));
addListAlias(kDH, filterByKeyExchange(allCiphers, new HashSet<>(Arrays.asList(KeyExchange.DHr, KeyExchange.DHd))));
addListAlias(kECDHr, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.ECDHr)));
addListAlias(kECDHe, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.ECDHe)));
addListAlias(kECDH, filterByKeyExchange(allCiphers, new HashSet<>(Arrays.asList(KeyExchange.ECDHe, KeyExchange.ECDHr))));
addListAlias(ECDH, filterByKeyExchange(allCiphers, new HashSet<>(Arrays.asList(KeyExchange.ECDHe, KeyExchange.ECDHr, KeyExchange.EECDH))));
addListAlias(kECDHE, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.EECDH)));
Set<Cipher> ecdhe = filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.EECDH));
remove(ecdhe, aNULL);
addListAlias(ECDHE, ecdhe);
addListAlias(kEECDH, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.EECDH)));
aliases.put(EECDHE, aliases.get(kEECDH));
Set<Cipher> eecdh = filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.EECDH));
eecdh.removeAll(filterByAuthentication(allCiphers, Collections.singleton(Authentication.aNULL)));
addListAlias(EECDH, eecdh);
addListAlias(aDSS, filterByAuthentication(allCiphers, Collections.singleton(Authentication.DSS)));
aliases.put(DSS, aliases.get(aDSS));
addListAlias(aDH, filterByAuthentication(allCiphers, Collections.singleton(Authentication.DH)));
Set<Cipher> aecdh = filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.EECDH));
addListAlias(AECDH, filterByAuthentication(aecdh, Collections.singleton(Authentication.aNULL)));
addListAlias(aECDH, filterByAuthentication(allCiphers, Collections.singleton(Authentication.ECDH)));
addListAlias(ECDSA, filterByAuthentication(allCiphers, Collections.singleton(Authentication.ECDSA)));
aliases.put(aECDSA, aliases.get(ECDSA));
addListAlias(kFZA, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.FZA)));
addListAlias(aFZA, filterByAuthentication(allCiphers, Collections.singleton(Authentication.FZA)));
addListAlias(eFZA, filterByEncryption(allCiphers, Collections.singleton(Encryption.FZA)));
addListAlias(FZA, filter(allCiphers, null, Collections.singleton(KeyExchange.FZA), Collections.singleton(Authentication.FZA), Collections.singleton(Encryption.FZA), null, null));
addListAlias(Constants.SSL_PROTO_TLSv1_2, filterByProtocol(allCiphers, Collections.singleton(Protocol.TLSv1_2)));
addListAlias(Constants.SSL_PROTO_TLSv1_0, filterByProtocol(allCiphers, Collections.singleton(Protocol.TLSv1)));
addListAlias(Constants.SSL_PROTO_SSLv3, filterByProtocol(allCiphers, Collections.singleton(Protocol.SSLv3)));
aliases.put(Constants.SSL_PROTO_TLSv1, aliases.get(Constants.SSL_PROTO_TLSv1_0));
addListAlias(Constants.SSL_PROTO_SSLv2, filterByProtocol(allCiphers, Collections.singleton(Protocol.SSLv2)));
addListAlias(DH, filterByKeyExchange(allCiphers, new HashSet<>(Arrays.asList(KeyExchange.DHr, KeyExchange.DHd, KeyExchange.EDH))));
Set<Cipher> adh = filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.EDH));
adh.retainAll(filterByAuthentication(allCiphers, Collections.singleton(Authentication.aNULL)));
addListAlias(ADH, adh);
addListAlias(AES128, filterByEncryption(allCiphers, new HashSet<>(Arrays.asList(Encryption.AES128, Encryption.AES128CCM, Encryption.AES128CCM8, Encryption.AES128GCM))));
addListAlias(AES256, filterByEncryption(allCiphers, new HashSet<>(Arrays.asList(Encryption.AES256, Encryption.AES256CCM, Encryption.AES256CCM8, Encryption.AES256GCM))));
addListAlias(AES, filterByEncryption(allCiphers, new HashSet<>(Arrays.asList(Encryption.AES128, Encryption.AES128CCM, Encryption.AES128CCM8, Encryption.AES128GCM, Encryption.AES256, Encryption.AES256CCM, Encryption.AES256CCM8, Encryption.AES256GCM))));
addListAlias(ARIA128, filterByEncryption(allCiphers, Collections.singleton(Encryption.ARIA128GCM)));
addListAlias(ARIA256, filterByEncryption(allCiphers, Collections.singleton(Encryption.ARIA256GCM)));
addListAlias(ARIA, filterByEncryption(allCiphers, new HashSet<>(Arrays.asList(Encryption.ARIA128GCM, Encryption.ARIA256GCM))));
addListAlias(AESGCM, filterByEncryption(allCiphers, new HashSet<>(Arrays.asList(Encryption.AES128GCM, Encryption.AES256GCM))));
addListAlias(AESCCM, filterByEncryption(allCiphers, new HashSet<>(Arrays.asList(Encryption.AES128CCM, Encryption.AES128CCM8, Encryption.AES256CCM, Encryption.AES256CCM8))));
addListAlias(AESCCM8, filterByEncryption(allCiphers, new HashSet<>(Arrays.asList(Encryption.AES128CCM8, Encryption.AES256CCM8))));
addListAlias(CAMELLIA, filterByEncryption(allCiphers, new HashSet<>(Arrays.asList(Encryption.CAMELLIA128, Encryption.CAMELLIA256))));
addListAlias(CAMELLIA128, filterByEncryption(allCiphers, Collections.singleton(Encryption.CAMELLIA128)));
addListAlias(CAMELLIA256, filterByEncryption(allCiphers, Collections.singleton(Encryption.CAMELLIA256)));
addListAlias(CHACHA20, filterByEncryption(allCiphers, Collections.singleton(Encryption.CHACHA20POLY1305)));
addListAlias(TRIPLE_DES, filterByEncryption(allCiphers, Collections.singleton(Encryption.TRIPLE_DES)));
addListAlias(DES, filterByEncryption(allCiphers, Collections.singleton(Encryption.DES)));
addListAlias(RC4, filterByEncryption(allCiphers, Collections.singleton(Encryption.RC4)));
addListAlias(RC2, filterByEncryption(allCiphers, Collections.singleton(Encryption.RC2)));
addListAlias(IDEA, filterByEncryption(allCiphers, Collections.singleton(Encryption.IDEA)));
addListAlias(SEED, filterByEncryption(allCiphers, Collections.singleton(Encryption.SEED)));
addListAlias(MD5, filterByMessageDigest(allCiphers, Collections.singleton(MessageDigest.MD5)));
addListAlias(SHA1, filterByMessageDigest(allCiphers, Collections.singleton(MessageDigest.SHA1)));
aliases.put(SHA, aliases.get(SHA1));
addListAlias(SHA256, filterByMessageDigest(allCiphers, Collections.singleton(MessageDigest.SHA256)));
addListAlias(SHA384, filterByMessageDigest(allCiphers, Collections.singleton(MessageDigest.SHA384)));
addListAlias(aGOST, filterByAuthentication(allCiphers, new HashSet<>(Arrays.asList(Authentication.GOST01, Authentication.GOST94))));
addListAlias(aGOST01, filterByAuthentication(allCiphers, Collections.singleton(Authentication.GOST01)));
addListAlias(aGOST94, filterByAuthentication(allCiphers, Collections.singleton(Authentication.GOST94)));
addListAlias(kGOST, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.GOST)));
addListAlias(GOST94, filterByMessageDigest(allCiphers, Collections.singleton(MessageDigest.GOST94)));
addListAlias(GOST89MAC, filterByMessageDigest(allCiphers, Collections.singleton(MessageDigest.GOST89MAC)));
addListAlias(PSK, filter(allCiphers, null, new HashSet<>(Arrays.asList(KeyExchange.PSK, KeyExchange.RSAPSK, KeyExchange.DHEPSK, KeyExchange.ECDHEPSK)), Collections.singleton(Authentication.PSK), null, null, null));
addListAlias(aPSK, filterByAuthentication(allCiphers, Collections.singleton(Authentication.PSK)));
addListAlias(kPSK, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.PSK)));
addListAlias(kRSAPSK, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.RSAPSK)));
addListAlias(kECDHEPSK, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.ECDHEPSK)));
addListAlias(kDHEPSK, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.DHEPSK)));
addListAlias(KRB5, filter(allCiphers, null, Collections.singleton(KeyExchange.KRB5), Collections.singleton(Authentication.KRB5), null, null, null));
addListAlias(aSRP, filterByAuthentication(allCiphers, Collections.singleton(Authentication.SRP)));
addListAlias(kSRP, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.SRP)));
addListAlias(SRP, filterByKeyExchange(allCiphers, Collections.singleton(KeyExchange.SRP)));
initialized = true;
// Despite what the OpenSSL docs say, DEFAULT also excludes SSLv2
addListAlias(DEFAULT, parse("ALL:!EXPORT:!eNULL:!aNULL:!SSLv2:!DES:!RC2:!RC4:!DSS:!SEED:!IDEA:!CAMELLIA:!AESCCM:!3DES:!ARIA"));
// COMPLEMENTOFDEFAULT is also not exactly as defined by the docs
LinkedHashSet<Cipher> complementOfDefault = filterByKeyExchange(all, new HashSet<>(Arrays.asList(KeyExchange.EDH,KeyExchange.EECDH)));
complementOfDefault = filterByAuthentication(complementOfDefault, Collections.singleton(Authentication.aNULL));
complementOfDefault.removeAll(aliases.get(eNULL));
complementOfDefault.addAll(aliases.get(Constants.SSL_PROTO_SSLv2));
complementOfDefault.addAll(aliases.get(EXPORT));
complementOfDefault.addAll(aliases.get(DES));
complementOfDefault.addAll(aliases.get(TRIPLE_DES));
complementOfDefault.addAll(aliases.get(RC2));
complementOfDefault.addAll(aliases.get(RC4));
complementOfDefault.addAll(aliases.get(aDSS));
complementOfDefault.addAll(aliases.get(SEED));
complementOfDefault.addAll(aliases.get(IDEA));
complementOfDefault.addAll(aliases.get(CAMELLIA));
complementOfDefault.addAll(aliases.get(AESCCM));
complementOfDefault.addAll(aliases.get(ARIA));
defaultSort(complementOfDefault);
addListAlias(COMPLEMENTOFDEFAULT, complementOfDefault);
}
static void addListAlias(String alias, Set<Cipher> ciphers) {
aliases.put(alias, new ArrayList<>(ciphers));
}
static void moveToEnd(final LinkedHashSet<Cipher> ciphers, final String alias) {
moveToEnd(ciphers, aliases.get(alias));
}
static void moveToEnd(final LinkedHashSet<Cipher> ciphers, final Collection<Cipher> toBeMovedCiphers) {
List<Cipher> movedCiphers = new ArrayList<>(toBeMovedCiphers);
movedCiphers.retainAll(ciphers);
ciphers.removeAll(movedCiphers);
ciphers.addAll(movedCiphers);
}
static void moveToStart(final LinkedHashSet<Cipher> ciphers, final Collection<Cipher> toBeMovedCiphers) {
List<Cipher> movedCiphers = new ArrayList<>(toBeMovedCiphers);
List<Cipher> originalCiphers = new ArrayList<>(ciphers);
movedCiphers.retainAll(ciphers);
ciphers.clear();
ciphers.addAll(movedCiphers);
ciphers.addAll(originalCiphers);
}
static void add(final LinkedHashSet<Cipher> ciphers, final String alias) {
ciphers.addAll(aliases.get(alias));
}
static void remove(final Set<Cipher> ciphers, final String alias) {
ciphers.removeAll(aliases.get(alias));
}
static LinkedHashSet<Cipher> strengthSort(final LinkedHashSet<Cipher> ciphers) {
/*
* This routine sorts the ciphers with descending strength. The sorting
* must keep the pre-sorted sequence, so we apply the normal sorting
* routine as '+' movement to the end of the list.
*/
Set<Integer> keySizes = new HashSet<>();
for (Cipher cipher : ciphers) {
keySizes.add(Integer.valueOf(cipher.getStrength_bits()));
}
List<Integer> strength_bits = new ArrayList<>(keySizes);
Collections.sort(strength_bits);
Collections.reverse(strength_bits);
final LinkedHashSet<Cipher> result = new LinkedHashSet<>(ciphers);
for (int strength : strength_bits) {
moveToEnd(result, filterByStrengthBits(ciphers, strength));
}
return result;
}
/*
* See
* https://github.com/openssl/openssl/blob/7c96dbcdab959fef74c4caae63cdebaa354ab252/ssl/ssl_ciph.c#L1371
*/
static LinkedHashSet<Cipher> defaultSort(final LinkedHashSet<Cipher> ciphers) {
final LinkedHashSet<Cipher> result = new LinkedHashSet<>(ciphers.size());
final LinkedHashSet<Cipher> ecdh = new LinkedHashSet<>(ciphers.size());
/* Everything else being equal, prefer ephemeral ECDH over other key exchange mechanisms */
ecdh.addAll(filterByKeyExchange(ciphers, Collections.singleton(KeyExchange.EECDH)));
/* AES is our preferred symmetric cipher */
Set<Encryption> aes = new HashSet<>(Arrays.asList(Encryption.AES128, Encryption.AES128CCM,
Encryption.AES128CCM8, Encryption.AES128GCM, Encryption.AES256,
Encryption.AES256CCM, Encryption.AES256CCM8, Encryption.AES256GCM));
/* Now arrange all ciphers by preference: */
result.addAll(filterByEncryption(ecdh, aes));
result.addAll(filterByEncryption(ciphers, aes));
/* Add everything else */
result.addAll(ecdh);
result.addAll(ciphers);
/* Low priority for MD5 */
moveToEnd(result, filterByMessageDigest(result, Collections.singleton(MessageDigest.MD5)));
/* Move anonymous ciphers to the end. Usually, these will remain disabled.
* (For applications that allow them, they aren't too bad, but we prefer
* authenticated ciphers.) */
moveToEnd(result, filterByAuthentication(result, Collections.singleton(Authentication.aNULL)));
/* Move ciphers without forward secrecy to the end */
moveToEnd(result, filterByAuthentication(result, Collections.singleton(Authentication.ECDH)));
moveToEnd(result, filterByKeyExchange(result, Collections.singleton(KeyExchange.RSA)));
moveToEnd(result, filterByKeyExchange(result, Collections.singleton(KeyExchange.PSK)));
/* RC4 is sort-of broken -- move the the end */
moveToEnd(result, filterByEncryption(result, Collections.singleton(Encryption.RC4)));
return strengthSort(result);
}
static Set<Cipher> filterByStrengthBits(Set<Cipher> ciphers, int strength_bits) {
Set<Cipher> result = new LinkedHashSet<>(ciphers.size());
for (Cipher cipher : ciphers) {
if (cipher.getStrength_bits() == strength_bits) {
result.add(cipher);
}
}
return result;
}
static Set<Cipher> filterByProtocol(Set<Cipher> ciphers, Set<Protocol> protocol) {
return filter(ciphers, protocol, null, null, null, null, null);
}
static LinkedHashSet<Cipher> filterByKeyExchange(Set<Cipher> ciphers, Set<KeyExchange> kx) {
return filter(ciphers, null, kx, null, null, null, null);
}
static LinkedHashSet<Cipher> filterByAuthentication(Set<Cipher> ciphers, Set<Authentication> au) {
return filter(ciphers, null, null, au, null, null, null);
}
static Set<Cipher> filterByEncryption(Set<Cipher> ciphers, Set<Encryption> enc) {
return filter(ciphers, null, null, null, enc, null, null);
}
static Set<Cipher> filterByEncryptionLevel(Set<Cipher> ciphers, Set<EncryptionLevel> level) {
return filter(ciphers, null, null, null, null, level, null);
}
static Set<Cipher> filterByMessageDigest(Set<Cipher> ciphers, Set<MessageDigest> mac) {
return filter(ciphers, null, null, null, null, null, mac);
}
static LinkedHashSet<Cipher> filter(Set<Cipher> ciphers, Set<Protocol> protocol, Set<KeyExchange> kx,
Set<Authentication> au, Set<Encryption> enc, Set<EncryptionLevel> level, Set<MessageDigest> mac) {
LinkedHashSet<Cipher> result = new LinkedHashSet<>(ciphers.size());
for (Cipher cipher : ciphers) {
if (protocol != null && protocol.contains(cipher.getProtocol())) {
result.add(cipher);
}
if (kx != null && kx.contains(cipher.getKx())) {
result.add(cipher);
}
if (au != null && au.contains(cipher.getAu())) {
result.add(cipher);
}
if (enc != null && enc.contains(cipher.getEnc())) {
result.add(cipher);
}
if (level != null && level.contains(cipher.getLevel())) {
result.add(cipher);
}
if (mac != null && mac.contains(cipher.getMac())) {
result.add(cipher);
}
}
return result;
}
public static LinkedHashSet<Cipher> parse(String expression) {
if (!initialized) {
init();
}
String[] elements = expression.split(SEPARATOR);
LinkedHashSet<Cipher> ciphers = new LinkedHashSet<>();
Set<Cipher> removedCiphers = new HashSet<>();
for (String element : elements) {
if (element.startsWith(DELETE)) {
String alias = element.substring(1);
if (aliases.containsKey(alias)) {
remove(ciphers, alias);
}
} else if (element.startsWith(EXCLUDE)) {
String alias = element.substring(1);
if (aliases.containsKey(alias)) {
removedCiphers.addAll(aliases.get(alias));
} else {
log.warn(sm.getString("jsse.openssl.unknownElement", alias));
}
} else if (element.startsWith(TO_END)) {
String alias = element.substring(1);
if (aliases.containsKey(alias)) {
moveToEnd(ciphers, alias);
}
} else if ("@STRENGTH".equals(element)) {
strengthSort(ciphers);
break;
} else if (aliases.containsKey(element)) {
add(ciphers, element);
} else if (element.contains(AND)) {
String[] intersections = element.split("\\" + AND);
if(intersections.length > 0 && aliases.containsKey(intersections[0])) {
List<Cipher> result = new ArrayList<>(aliases.get(intersections[0]));
for(int i = 1; i < intersections.length; i++) {
if(aliases.containsKey(intersections[i])) {
result.retainAll(aliases.get(intersections[i]));
}
}
ciphers.addAll(result);
}
}
}
ciphers.removeAll(removedCiphers);
return ciphers;
}
public static List<String> convertForJSSE(Collection<Cipher> ciphers) {
List<String> result = new ArrayList<>(ciphers.size());
for (Cipher cipher : ciphers) {
result.addAll(cipher.getJsseNames());
}
if (log.isDebugEnabled()) {
log.debug(sm.getString("jsse.openssl.effectiveCiphers", displayResult(ciphers, true, ",")));
}
return result;
}
/**
* Parse the specified expression according to the OpenSSL syntax and
* returns a list of standard JSSE cipher names.
*
* @param expression the openssl expression to define a list of cipher.
* @return the corresponding list of ciphers.
*/
public static List<String> parseExpression(String expression) {
return convertForJSSE(parse(expression));
}
/**
* Converts a JSSE cipher name to an OpenSSL cipher name.
*
* @param jsseCipherName The JSSE name for a cipher
*
* @return The OpenSSL name for the specified JSSE cipher
*/
public static String jsseToOpenSSL(String jsseCipherName) {
if (!initialized) {
init();
}
return jsseToOpenSSL.get(jsseCipherName);
}
/**
* Converts an OpenSSL cipher name to a JSSE cipher name.
*
* @param opensslCipherName The OpenSSL name for a cipher
*
* @return The JSSE name for the specified OpenSSL cipher. If none is known,
* the IANA standard name will be returned instead
*/
public static String openSSLToJsse(String opensslCipherName) {
if (!initialized) {
init();
}
List<Cipher> ciphers = aliases.get(opensslCipherName);
if (ciphers == null || ciphers.size() != 1) {
// Not an OpenSSL cipher name
return null;
}
Cipher cipher = ciphers.get(0);
// Each Cipher always has at least one JSSE name
return cipher.getJsseNames().iterator().next();
}
static String displayResult(Collection<Cipher> ciphers, boolean useJSSEFormat, String separator) {
if (ciphers.isEmpty()) {
return "";
}
StringBuilder builder = new StringBuilder(ciphers.size() * 16);
for (Cipher cipher : ciphers) {
if (useJSSEFormat) {
for (String name : cipher.getJsseNames()) {
builder.append(name);
builder.append(separator);
}
} else {
builder.append(cipher.getOpenSSLAlias());
}
builder.append(separator);
}
return builder.toString().substring(0, builder.length() - 1);
}
public static void usage() {
System.out.println("Usage: java " + OpenSSLCipherConfigurationParser.class.getName() + " [options] cipherspec");
System.out.println();
System.out.println("Displays the TLS cipher suites matching the cipherspec.");
System.out.println();
System.out.println(" --help,");
System.out.println(" -h Print this help message");
System.out.println(" --openssl Show OpenSSL cipher suite names instead of IANA cipher suite names.");
System.out.println(" --verbose,");
System.out.println(" -v Provide detailed cipher listing");
}
public static void main(String[] args) throws Exception
{
boolean verbose = false;
boolean useOpenSSLNames = false;
int argindex;
for(argindex = 0; argindex < args.length; ++argindex)
{
String arg = args[argindex];
if("--verbose".equals(arg) || "-v".equals(arg))
verbose = true;
else if("--openssl".equals(arg))
useOpenSSLNames = true;
else if("--help".equals(arg) || "-h".equals(arg)) {
usage();
System.exit(0);
}
else if("--".equals(arg)) {
++argindex;
break;
} else if(arg.startsWith("-")) {
System.out.println("Unknown option: " + arg);
usage();
System.exit(1);
} else {
// Non-switch argument... probably the cipher spec
break;
}
}
String cipherSpec;
if(argindex < args.length) {
cipherSpec = args[argindex];
} else {
cipherSpec = "DEFAULT";
}
Set<Cipher> ciphers = parse(cipherSpec);
boolean first = true;
if(null != ciphers && 0 < ciphers.size()) {
for(Cipher cipher : ciphers)
{
if(first) {
first = false;
} else {
if(!verbose)
System.out.print(',');
}
if(useOpenSSLNames)
System.out.print(cipher.getOpenSSLAlias());
else
System.out.print(cipher.name());
if(verbose) {
System.out.println("\t" + cipher.getProtocol() + "\tKx=" + cipher.getKx() + "\tAu=" + cipher.getAu() + "\tEnc=" + cipher.getEnc() + "\tMac=" + cipher.getMac());
}
}
System.out.println();
} else {
System.out.println("No ciphers match '" + cipherSpec + "'");
}
}
}

View File

@@ -0,0 +1,44 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.util.net.openssl.ciphers;
import org.apache.tomcat.util.net.Constants;
enum Protocol {
SSLv3(Constants.SSL_PROTO_SSLv3),
SSLv2(Constants.SSL_PROTO_SSLv2),
TLSv1(Constants.SSL_PROTO_TLSv1),
TLSv1_2(Constants.SSL_PROTO_TLSv1_2),
TLSv1_3(Constants.SSL_PROTO_TLSv1_3);
private final String openSSLName;
private Protocol(String openSSLName) {
this.openSSLName = openSSLName;
}
/**
* The name returned by OpenSSL in the protocol column when using
* <code>openssl ciphers -v</code>. This is currently only used by the unit
* tests hence it is package private.
*/
String getOpenSSLName() {
return openSSLName;
}
}