سؤال

أحاول استخدام Keytool (Java) لإنشاء شهادة موقعة ذاتيا ولكن عندما أحاول استخدامه، أحصل على الاستثناء التالي (انظر أسفل الاستثناء بأكمله).

...<5 more exceptions above this>
Caused by: sun.security.validator.ValidatorException: No trusted certificate found
        at sun.security.validator.SimpleValidator.buildTrustedChain(SimpleValidator.java:304)
        at sun.security.validator.SimpleValidator.engineValidate(SimpleValidator.java:107)
        at sun.security.validator.Validator.validate(Validator.java:203)
        at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:172)
        at com.sun.net.ssl.internal.ssl.JsseX509TrustManager.checkServerTrusted(SSLContextImpl.java:320)
        at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:841)
        ... 22 more

أعلم أنه يمكنني تمرير هذا مع هذا الرمز:

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;

HostnameVerifier hv = new HostnameVerifier() {
    public boolean verify(String urlHostName, SSLSession session) {
        System.out.println("Warning: URL Host: " + urlHostName + " vs. " + session.getPeerHost());
        return true;
    }
};

HttpsURLConnection.setDefaultHostnameVerifier(hv);

(مصدر)

لكنني غير مهتم بهذه الحلول لأنني أعتقد أنه يخلق حفرة أمنية. (يرجى تصحيح لي إذا كنت مخطئا).

يمكن لأي شخص لي نقطة في الاتجاه الصحيح؟ أنا اختبار محليا في الوقت الحالي الآن حتى يسهل تغيير الأشياء. لدي حق الوصول إلى رمز الخادم ورمز العميل وإلى ملف .keystore.

تحديث

كنت أحاول استخدام ملف واحد .keystore لكل من العميل والخادم ولكن على أمل تبسيط مشكلاتي، قمت بإنشاء Server.keystore (انظر أدناه) والعميل. TestrustStore (انظر أدناه). أنا واثق بشكل معقول من أن المصادقة صحيحة ولكن إذا كان شخص ما يمكن التحقق من أنني سأكون ممتنا.

server.keystore.

hostname[username:/this/is/a/path][711]% keytool -list -keystore server.keystore -v
Enter keystore password:

Keystore type: JKS
Keystore provider: SUN

Your keystore contains 1 entry

Alias name: hostname
Creation date: Feb 4, 2010
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=hostname, OU=hostname, O=hostname, L=hostname, ST=hostname, C=hostname
Issuer: CN=hostname, OU=hostname, O=hostname, L=hostname, ST=hostname, C=hostname
Serial number: 4b6b0ea7
Valid from: Thu Feb 04 13:15:03 EST 2010 until: Wed May 05 14:15:03 EDT 2010
Certificate fingerprints:
         MD5:  81:C0:3F:EC:AD:5B:7B:C4:DA:08:CC:D7:11:1F:1D:38
         SHA1: F1:78:AD:C8:D0:3A:4C:0C:9A:4F:89:C0:2A:2F:E2:E6:D5:13:96:40
         Signature algorithm name: SHA1withDSA
         Version: 3


*******************************************
*******************************************

client.truststore.

hostname[username:/this/is/a/path][713]% keytool -list -keystore client.truststore -v
Enter keystore password:

Keystore type: JKS
Keystore provider: SUN

Your keystore contains 1 entry

Alias name: mykey
Creation date: Feb 4, 2010
Entry type: trustedCertEntry

Owner: CN=hostname, OU=hostname, O=hostname, L=hostname, ST=hostname, C=hostname
Issuer: CN=hostname, OU=hostname, O=hostname, L=hostname, ST=hostname, C=hostname
Serial number: 4b6b0ea7
Valid from: Thu Feb 04 13:15:03 EST 2010 until: Wed May 05 14:15:03 EDT 2010
Certificate fingerprints:
         MD5:  81:C0:3F:EC:AD:5B:7B:C4:DA:08:CC:D7:11:1F:1D:38
         SHA1: F1:78:AD:C8:D0:3A:4C:0C:9A:4F:89:C0:2A:2F:E2:E6:D5:13:96:40
         Signature algorithm name: SHA1withDSA
         Version: 3


*******************************************
*******************************************

تحديث

اعتقدت أنه قد يكون من المفيد تضمين الاستثناء بأكمله:

javax.xml.soap.SOAPException: java.io.IOException: Could not transmit message
        at org.jboss.ws.core.soap.SOAPConnectionImpl.callInternal(SOAPConnectionImpl.java:115)
        at org.jboss.ws.core.soap.SOAPConnectionImpl.call(SOAPConnectionImpl.java:66)
        at com.alcatel.tpapps.common.utils.SOAPClient.execute(SOAPClient.java:193)
        at com.alcatel.tpapps.common.utils.SOAPClient.main(SOAPClient.java:280)
Caused by: java.io.IOException: Could not transmit message
        at org.jboss.ws.core.client.RemotingConnectionImpl.invoke(RemotingConnectionImpl.java:192)
        at org.jboss.ws.core.client.SOAPRemotingConnection.invoke(SOAPRemotingConnection.java:77)
        at org.jboss.ws.core.soap.SOAPConnectionImpl.callInternal(SOAPConnectionImpl.java:106)
        ... 3 more
Caused by: org.jboss.remoting.CannotConnectException: Can not connect http client invoker. sun.security.validator.ValidatorException: No trusted certificate found.
        at org.jboss.remoting.transport.http.HTTPClientInvoker.useHttpURLConnection(HTTPClientInvoker.java:368)
        at org.jboss.remoting.transport.http.HTTPClientInvoker.transport(HTTPClientInvoker.java:148)
        at org.jboss.remoting.MicroRemoteClientInvoker.invoke(MicroRemoteClientInvoker.java:141)
        at org.jboss.remoting.Client.invoke(Client.java:1858)
        at org.jboss.remoting.Client.invoke(Client.java:718)
        at org.jboss.ws.core.client.RemotingConnectionImpl.invoke(RemotingConnectionImpl.java:171)
        ... 5 more
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate found
        at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:150)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1584)
        at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:174)
        at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:168)
        at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:848)
        at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:106)
        at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:495)
        at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:433)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:877)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1089)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1116)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1100)
        at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:402)
        at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:170)
        at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:857)
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230)
        at org.jboss.remoting.transport.http.HTTPClientInvoker.useHttpURLConnection(HTTPClientInvoker.java:288)
        ... 10 more
Caused by: sun.security.validator.ValidatorException: No trusted certificate found
        at sun.security.validator.SimpleValidator.buildTrustedChain(SimpleValidator.java:304)
        at sun.security.validator.SimpleValidator.engineValidate(SimpleValidator.java:107)
        at sun.security.validator.Validator.validate(Validator.java:203)
        at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:172)
        at com.sun.net.ssl.internal.ssl.JsseX509TrustManager.checkServerTrusted(SSLContextImpl.java:320)
        at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:841)
        ... 22 more
هل كانت مفيدة؟

المحلول

ستحتاج إلى "إنشاء الثقة" بين الخادم والعميل (أنا بحاجة فقط إلى القيام بمصادقة جانب الخادم). هذا لأنك تستخدم Certs موقعة ذاتيا. التي تنطوي على استيراد سيرتك الخادم الخاصة بك في متجر ائتمان العميل:

على جانب الخادم:

keytool -keystore <keystore file> -alias <alias> -export -file <certfilename>.cert

نسخ ملف .cert إلى جانب العميل ثم:

keytool -keystore <truststore file> -alias <alias> -import -file <certfilename>.cert

نصائح أخرى

لا يمكنك مشاركة Keystore بين العميل والخادم، لأن KeyStore يحتوي على المفتاح الخاص. عند المصادقة، يتخطى العميل الشهادات مع مفاتيح خاصة. كما قيل أعلاه تحتاج إلى نشر مؤشر طعث على جانب العميل.

الشهادات في Keystore لا تتصرف بنفس الطريقة، اعتمادا على كيفية إنشاءها أو استيرادها.

نوع دخول الشهادة المستوردة (ينظر إليه عندما يسرد الترفيح بشكل كامل -list -v) هو "الثقة فيكيرتن". نوع إدخال الشهادة الناتج هو "primactykeyentry". عند تصدير شهادة، تقوم فقط بتصدير المفتاح العمومي فقط، والرجوعية الاختيارية إلى مصدرها.

يبدو أنك بحاجة إلى تصدير الشهادة الموقعة ذاتيا في Keystore الخاص بك كشهادة موثوق بها في TrustStore (الأسماء)

لن أفعل ذلك، لأن تطبيقات SSL / TLS ربما لا تدعمها. من منظور عالمي حقيقي، يشبه نشر المفتاح الخاص السرية السرية في نهاية المطاف من VeriSign على بعض خادم الويب الغامض لتوقيع الصفحات غير الرسمية، في حين أن الغرض الوحيد من هذا المفتاح الخاص هو البقاء في شهادات آمنة وتوقيعها. ربما لن يقوم منفذي SSL / TLS بتلوث كودهم بمثل هذه الحالة الاستخدام، وعلى أي حال، قد يقوم ملحق الشهادة "Keyusage" بتقييد استخدام الشهادة للتوقيع، ومنع التشفير.

لهذا السبب أقترح إعادة بناء سلسلة من الشهادات للاختبار الخاص بك.

يحتوي وثائق Keytool على جزء مثير للاهتمام حول إنشاء سلسلة (-gencert الأمر) لكنه مثال للهيكل العظمي الذي لا يغطي علاقة Keystore-TrustStore. لقد عززتها لمحاكاة سلطة شهادات تابعة لجهة خارجية.

متجر مؤقت their-keystore.jks يمثل سلطة تنبعث منها الشهادة. أطعمه مع سلسلة شهادة من ca2 -> ca1 -> ca مع ca يجري النظر في شهادة الجذر. تظهر السلسلة مع كل شهادة غير جذر (وهي ca1 و ca2) الرجوع إلى مصدرها كما Certificate[2]. وبعد يرجى ملاحظة أن كل شهادة "PrimactKeyEnentry".

ثم أطعم my-keystore.jks مع تلك الشهادات بالترتيب: ca, ca1, ca2. وبعد استيراد ca مع ال -trustcacerts الخيار الذي يعني أنه يصبح شهادة جذرية. في my-keystore.jks كل شهادة مستوردة الآن هي "TrustCedCerTentry" مما يعني أنه لا يوجد سوى المفتاح العمومي. تظهر العلاقة الإصدار فقط في حقل "المصدر" ولكن لا بأس لأن علاقة الثقة المسألة أكثر في وقت الاستيراد.

عند هذه النقطة my-keystore.jks يحاكي بيئة تحتوي على بعض الشهادات الموثوق بها، مثل جري جديدا. ال their-keystore.jks يحاكي مالكي هذه الشهادات، الذين لديهم القدرة على تسجيل طلبات الشهادة.

لذلك أنا: أنا خلق شهادة موقعة ذاتيا e1 في my-keystore.jks, ، الحصول عليها الموقع ca2 (عبر their-keystore.jks) واستيراد النتيجة الموقعة مرة أخرى إلى my-keystore.jks. e1 لا يزال "primactykeyentry" (لأن المفتاح الخاص يبقى في my-keystore.jks) ولكن الآن لقد بنيت السلسلة التالية: e1 -> ca2 -> ca1. وبعد يبدو أن ca1 -> ca ضمني مع ca كونه سلطة شهادة.

لبناء TrustStore أنا فقط استيراد الشهادات ca, ca1 و ca2 بنفس الطريقة التي فعلت بها my-keystore.jks. وبعد يرجى ملاحظة أنني لا استيراد e1, ، كما أتوقع عميل SSL / TLS للتحقق من صحةه ca2.

أعتقد أن هذا يغلق إلى حد ما كيف تعمل الأمور في العالم الحقيقي. ما هو لطيف هنا هو أن لديك سيطرة كاملة على الشهادات، ولا اعتماد على Cacerts JRE.

هنا هو رمز وضع ما أقوله في الممارسة العملية. يبدو أنه يعمل مع Jetty (العميل والخادم) طالما كنت تعطيل قائمة إلغاء الشهادات (موضوع يترك ليوم آخر).

#!/bin/bash

rm  their-keystore.jks 2> /dev/null
rm  my-keystore.jks    2> /dev/null
rm  my-truststore.jks  2> /dev/null

echo "===================================================="
echo "Creating fake third-party chain ca2 -> ca1 -> ca ..."
echo "===================================================="

keytool -genkeypair -alias ca  -dname cn=ca                           \
  -validity 10000 -keyalg RSA -keysize 2048                           \
  -ext BasicConstraints:critical=ca:true,pathlen:10000                \
  -keystore their-keystore.jks -keypass Keypass -storepass Storepass

keytool -genkeypair -alias ca1 -dname cn=ca1                          \
  -validity 10000 -keyalg RSA -keysize 2048                           \
  -keystore their-keystore.jks -keypass Keypass -storepass Storepass

keytool -genkeypair -alias ca2 -dname cn=ca2                          \
  -validity 10000 -keyalg RSA -keysize 2048                           \
  -keystore their-keystore.jks -keypass Keypass -storepass Storepass


  keytool -certreq -alias ca1                                            \
    -keystore their-keystore.jks -keypass Keypass -storepass Storepass   \
| keytool -gencert -alias ca                                             \
    -ext KeyUsage:critical=keyCertSign                                   \
    -ext SubjectAlternativeName=dns:ca1                                  \
    -keystore their-keystore.jks -keypass Keypass -storepass Storepass   \
| keytool -importcert -alias ca1                                         \
    -keystore   their-keystore.jks -keypass Keypass -storepass Storepass

#echo "Debug exit" ; exit 0

  keytool -certreq -alias ca2                                           \
    -keystore their-keystore.jks -keypass Keypass -storepass Storepass  \
| keytool -gencert -alias ca1                                           \
    -ext KeyUsage:critical=keyCertSign                                  \
    -ext SubjectAlternativeName=dns:ca2                                 \
    -keystore their-keystore.jks -keypass Keypass -storepass Storepass  \
| keytool -importcert -alias ca2                                        \
    -keystore their-keystore.jks -keypass Keypass -storepass Storepass

keytool -list -v -storepass Storepass -keystore their-keystore.jks


echo  "===================================================================="
echo  "Fake third-party chain generated. Now generating my-keystore.jks ..."
echo  "===================================================================="
read -p "Press a key to continue."

# Import authority's certificate chain

  keytool -exportcert -alias ca                                         \
    -keystore their-keystore.jks -keypass Keypass -storepass Storepass  \
| keytool -importcert -trustcacerts -noprompt -alias ca                 \
    -keystore  my-keystore.jks -keypass Keypass -storepass Storepass

  keytool -exportcert -alias ca1                                        \
    -keystore their-keystore.jks -keypass Keypass -storepass Storepass  \
| keytool -importcert -noprompt -alias ca1                              \
    -keystore  my-keystore.jks -keypass Keypass -storepass Storepass

  keytool -exportcert -alias ca2                                        \
    -keystore their-keystore.jks -keypass Keypass -storepass Storepass  \
| keytool -importcert -noprompt -alias ca2                              \
    -keystore  my-keystore.jks -keypass Keypass -storepass Storepass

# Create our own certificate, the authority signs it.

keytool -genkeypair -alias e1  -dname cn=e1                        \
  -validity 10000 -keyalg RSA -keysize 2048                        \
  -keystore my-keystore.jks -keypass Keypass -storepass Storepass

  keytool -certreq -alias e1                                            \
    -keystore my-keystore.jks -keypass Keypass -storepass Storepass     \
| keytool -gencert -alias ca2                                           \
    -ext SubjectAlternativeName=dns:localhost                           \
    -ext KeyUsage:critical=keyEncipherment,digitalSignature             \
    -ext ExtendedKeyUsage=serverAuth,clientAuth                         \
    -keystore their-keystore.jks -keypass Keypass -storepass Storepass  \
| keytool -importcert -alias e1                                         \
    -keystore my-keystore.jks -keypass Keypass -storepass Storepass

keytool -list -v  -storepass Storepass -keystore  my-keystore.jks

echo "================================================="
echo "Keystore generated. Now generating truststore ..."
echo "================================================="
read -p "Press a key to continue."

  keytool -exportcert -alias ca                                        \
    -keystore my-keystore.jks -keypass Keypass -storepass Storepass    \
| keytool -importcert -trustcacerts -noprompt -alias ca                \
    -keystore my-truststore.jks -keypass Keypass -storepass Storepass

  keytool -exportcert -alias ca1                                       \
    -keystore my-keystore.jks -keypass Keypass -storepass Storepass    \
| keytool -importcert -noprompt -alias ca1                             \
    -keystore my-truststore.jks -keypass Keypass -storepass Storepass

  keytool -exportcert -alias ca2                                       \
    -keystore my-keystore.jks -keypass Keypass -storepass Storepass    \
| keytool -importcert -noprompt -alias ca2                             \
    -keystore my-truststore.jks -keypass Keypass -storepass Storepass

keytool -list -v  -storepass Storepass -keystore  my-truststore.jks

rm  their-keystore.jks 2> /dev/null

يجب أن لا تفعل ذلك. لوحة المفاتيح خاصة بصرامة. إذا كنت تسربها إلى أي شخص، فقد تعرضت للتأهيل بشكل قاتل. لا يوجد نقطة في القيام بهذا النوع من الأشياء فقط للحصول عليه، لأنه ليس كذلك العمل - إنه مجرد خرق أمني. عليك أن تفعل ذلك بشكل صحيح: تصدير من Keystore الخادم في ResultStore Client's TrustStore، ومن المفتاح Client's Keystore إذا كان أي مفتاح خادم Keystore.

أنا لا أفهم ذلك. هل تستخدم مخزن المفتاح الخادم مع العميل؟ ما هي حالة استخدامك بالضبط؟ هل تحاول إعداد المصادقة المتبادلة؟

إذا كانت الإجابة بنعم، فأنت على الطريق الخطأ هنا. ستحتاج إلى متجر مفتاح العميل (للحصول على شهادة العميل الموقعة ذاتيا والمفتاح الخاص) ومتجر ثقة عميل (للحصول على الشهادة المذكورة ذاتيا "الخادم"، أي دون مفتاح خاص به). كلاهما مختلف عن متجر خادم الخادم.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top