रखते हुए प्रोग्रामेटिक रूप से प्रमाण पत्र प्राधिकरण जोड़ें StackOverflow पर इस विषय के बारे में बहुत सारे प्रश्न हैं, लेकिन मुझे मेरी समस्या से संबंधित कोई नहीं लगता है।एंड्रॉइड सिस्टम एसएसएल प्रमाणपत्र
मेरे पास एक एंड्रॉइड एप्लिकेशन है जिसे HTTPS सर्वर के साथ संवाद करने की आवश्यकता है: कुछ एंड्रॉइड सिस्टम कीस्टोर (सामान्य HTTPS वेबसाइट) में पंजीकृत सीए के साथ हस्ताक्षर किए गए हैं, और कुछ ने सीए के साथ हस्ताक्षर किए हैं लेकिन एंड्रॉइड सिस्टम कीस्टोर में नहीं हैं (उदाहरण के लिए एक स्वत: हस्ताक्षरित प्रमाणपत्र वाला एक सर्वर)।
मुझे पता है कि मेरे सीए प्रोग्रामेटिक रूप से कैसे जोड़ना है और इसका उपयोग करने के लिए प्रत्येक HTTPS कनेक्शन को मजबूर करना है। मैं निम्नलिखित कोड का उपयोग करें:
public class SslCertificateAuthority {
public static void addCertificateAuthority(InputStream inputStream) {
try {
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = new BufferedInputStream(inputStream);
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
// Tell the URLConnection to use a SocketFactory from our SSLContext
HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
हालांकि, कर कि एंड्रॉयड प्रणाली कुंजीस्टोर के उपयोग को अक्षम कर देता है, और मैं HTTPS क्वेरी नहीं कर सकता साइटों अन्य सीए किसी भी अधिक के साथ हस्ताक्षर किए। (एक अपवाद शुरू की है)
KeyStore.getInstance("AndroidCAStore")
... लेकिन मैं तो यह मेरे सीए नहीं जोड़ सकते हैं:
मैं एंड्रॉयड कुंजीस्टोर में मेरी CA जोड़ने की कोशिश की, का उपयोग करते हुए।
मैं अपने सीए का उपयोग करने के मामले के मामले में मामले के आधार पर स्थिर वैश्विक HttpsURLConnection.setDefaultSSLSocketFactory(...)
के बजाय उदाहरण विधि HttpsURLConnection.setSSLSocketFactory(...)
का उपयोग कर सकता हूं।
लेकिन यह व्यावहारिक नहीं है, क्योंकि कभी-कभी मैं कुछ पुस्तकालयों में पूर्व-कॉन्फ़िगर किए गए HttpsURLConnection
ऑब्जेक्ट को पास नहीं कर सकता।
कुछ विचार मैं कैसे कर सकता हूं?
संपादित करें - उत्तर
ठीक है, यह देखते हुए सलाह के बाद, यहाँ मेरे कार्य कोड है। इसे कुछ संवर्द्धन की आवश्यकता हो सकती है, लेकिन ऐसा लगता है कि यह एक शुरुआती बिंदु के रूप में काम करता है।
public class SslCertificateAuthority {
private static class UnifiedTrustManager implements X509TrustManager {
private X509TrustManager defaultTrustManager;
private X509TrustManager localTrustManager;
public UnifiedTrustManager(KeyStore localKeyStore) throws KeyStoreException {
try {
this.defaultTrustManager = createTrustManager(null);
this.localTrustManager = createTrustManager(localKeyStore);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
private X509TrustManager createTrustManager(KeyStore store) throws NoSuchAlgorithmException, KeyStoreException {
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init((KeyStore) store);
TrustManager[] trustManagers = tmf.getTrustManagers();
return (X509TrustManager) trustManagers[0];
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
try {
defaultTrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException ce) {
localTrustManager.checkServerTrusted(chain, authType);
}
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
try {
defaultTrustManager.checkClientTrusted(chain, authType);
} catch (CertificateException ce) {
localTrustManager.checkClientTrusted(chain, authType);
}
}
@Override
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] first = defaultTrustManager.getAcceptedIssuers();
X509Certificate[] second = localTrustManager.getAcceptedIssuers();
X509Certificate[] result = Arrays.copyOf(first, first.length + second.length);
System.arraycopy(second, 0, result, first.length, second.length);
return result;
}
}
public static void setCustomCertificateAuthority(InputStream inputStream) {
try {
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = new BufferedInputStream(inputStream);
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore and system CA
UnifiedTrustManager trustManager = new UnifiedTrustManager(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new TrustManager[]{trustManager}, null);
// Tell the URLConnection to use a SocketFactory from our SSLContext
HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
क्या आप सुनिश्चित हैं कि आपका कोड दोनों विश्वसनीय प्रमाण और स्वयं हस्ताक्षरित दोनों के साथ काम कर रहा है? मैंने कोशिश की है, यह केवल इनपुट स्ट्रीम से उस प्रमाणपत्र के साथ काम करता है; जब मैं विश्वसनीय प्रमाणपत्र के साथ सर्वर पर स्विच करता हूं, विधि "चेकसेवर ट्रस्टेड" अपवाद बढ़ता है –
क्या आपका परीक्षण एंड्रॉइड एन या पिछले संस्करण के साथ किया गया था? –
मैंने 4.4, 6.0 –