2014-07-07 2 views
3

우리 서버 중 하나에서 예정대로 실행되는 .net 코드를 작성 중입니다. 실행의 일부는 SSL을 통해 일부 웹 자원 및 서비스와 통신하는 Java 실행 파일을 실행해야합니다.원격 호스트에서 X509 인증서 체인을 자동으로 다운로드

자바가 SSL을 통해 무언가를하고 있으며 원격 인증서의 체인에있는 모든 단일 인증서를 갖고 있지 않다면 Java는 절대적으로 적합합니다. 그래서 .net에서 https : // [뭐든지] .com 리소스를 특정 할 수 있어야하고 로컬에서 전체 원격 체인을 다운로드해야합니다.

왜 자동으로 처리하고 싶습니까? 배포를 간소화하고 오라클의 인증서 중 하나가 만료 될 때마다이 작업을 4 회 수행하고 다시 수행하지 않아도되기를 원합니다.

나는이 일을하고있다 :

X509Certificate2 lowestCert = SecurityHelper.DownloadSslCertificate(keyDownloadLocation); 

     X509Chain chain = new X509Chain(); 
     chain.Build(lowestCert); 

     int counter = 0; 
     foreach (X509ChainElement el in chain.ChainElements) { 
      //Extract certificate 
      X509Certificate2 chainCert = el.Certificate; 

      //Come up with an alias and save location 
      string alias = certBaseName + counter; 
      string localLocation = Path.GetDirectoryName(
        System.Reflection.Assembly.GetEntryAssembly().Location 
        ) + @"\" +alias + ".cer"; 

      //Save it locally 
      SecurityHelper.SaveCertificateToFile(chainCert, localLocation); 

      //Remove (if possible) and add to java's keystore 
      deleteKeyFromKeystore(
        javaFolder, 
        alias, 
        certKeyStore, 
        SecurityHelper.GetEncryptedAppSetting("JavaKeystorePassword") 
      ); 

      addKeytoKeyStore(
        localLocation, 
        javaFolder, 
        alias, 
        certKeyStore, 
        SecurityHelper.GetEncryptedAppSetting("JavaKeystorePassword") 
      ); 

      //Then delete 
      if (File.Exists(localLocation)) File.Delete(localLocation); 

      counter++; 
     } 

SecurityHelper.DownloadSslCertificate는 웹 사이트의 URL에서 X509Certificate2를 생성하는 사용자 정의 방법이다.

"cert"는 가장 낮은 수준의 인증서이며이를 다시 얻을 수는 있지만 내가 할 수없는 일은 사슬에서 모든 것을 얻는 것입니다. chain.ChainElements는 체인의 나머지가 아직 기계에 설치되어 있지 않은 경우 여전히 1 레벨 깊이입니다. 내 문제는 이것이 (컴퓨터에) 완전히 알려지지 않은 새로운 URL이며, 스택을 올라가서 모든 것을 다운로드하고 싶다.

기계에 알려지지 않은 URL을 치고 체인의 모든 인증서를 프로그래밍 방식으로 다운로드하는 방법이 있습니까?

편집 :

public static X509Certificate2 DownloadSslCertificate(string strDNSEntry) 
    { 
     X509Certificate2 cert = null; 
     using (TcpClient client = new TcpClient()) 
     { 
      client.Connect(strDNSEntry, 443); 

      SslStream ssl = new SslStream(client.GetStream(), false, 
       new RemoteCertificateValidationCallback(
         (sender, certificate, chain, sslPolicyErrors) => { 
          return true; 
         } 
        ), null); 
      try 
      { 
       ssl.AuthenticateAsClient(strDNSEntry); 
      } 
      catch (AuthenticationException e) 
      { 
       ssl.Close(); 
       client.Close(); 
       return cert; 
      } 
      catch (Exception e) 
      { 
       ssl.Close(); 
       client.Close(); 
       return cert; 
      } 
      cert = new X509Certificate2(ssl.RemoteCertificate); 
      ssl.Close(); 
      client.Close(); 
      return cert; 
     } 
    } 

편집 # 2 나를 위해 일한 원격 SSL 인증서를 얻기 위해이 솔루션은 검증 콜백 체인을 포착했다 : 나는 어 다운로드있어 어떻게 여기가 SSL 인증서입니다 SslStream.AuthenticateAsClient (url) 중에 발생합니다. AuthenticateAsClient는 로컬 "callbackChainElements 완료 시간에 의해 다음

public static X509Certificate2 DownloadSslCertificate(string url) 
{ 
    X509Certificate2 cert = null; 
    using (TcpClient client = new TcpClient()) 
    { 
     client.Connect(url, 443); 

     SslStream ssl = new SslStream(client.GetStream(), false, CertificateValidationCallback, null); 
     try 
     { 
      ssl.AuthenticateAsClient(url); //will call CertificateValidationCallback 
     } 

... 등

:

private static X509ChainElementCollection callbackChainElements = null; 
private static bool CertificateValidationCallback(
    Object sender, 
    X509Certificate certificate, 
    X509Chain chain, 
    SslPolicyErrors sslPolicyErrors) 
{ 
    callbackChainElements = chain.ChainElements; 
    return true; 
} 

그리고이 콜백으로 검증 킥오프하는, 내가 좋아하는 일을했다 "변수는 X509ChainElement 컬렉션으로 설정됩니다.

답변

4

사실 Powershell을 사용하여 이와 비슷한 작업을 수행했습니다.

SSL 인증을 무시하도록 ServicePointManager가 변경되었습니다 (로컬에서 루트 인증서를 갖고 있지 않기 때문에 소리가납니다). true로 설정하려는 ServerCertificateValidationCallback입니다.이 값은 사용자 정의 유효성 검사 (또는 유효하지 않은 경우)를 사용하고 있음을 나타냅니다.

거기에서 체인점 요소를 확인할 수 있습니다. 당신은 바이트 배열에 인증서를 내보내려면 내보내기 방법을 사용할 수 있습니다 : 당신이 바이트 배열로 원하는 일을 단지 문제

foreach (X509ChainElement el in chain.ChainElements) { 
var certToCreate = el.Certificate.Export(X509ContentType.Cert); 
    ... 
} 

거기에서.다른 인증서 객체의 생성자에 전달할 수 있습니다. 그런 다음 Java 키 저장소로 가져올 수 있습니다.

도움이 되었으면 더 궁금한 점이 있으면 알려주세요.

편집 : 사실이 게시물은 tips working with X.509 certificates in .NET에 있습니다. 저자는 정리되지 않은 디렉토리에 임시 파일을 작성하기 때문에 바이트 배열에서 직접 작성하지 말 것을 권장합니다. 그래서 그의 제안은 디스크에 바이트 어레이를 작성한 다음 완료되면 수동으로 정리하는 것입니다.

+0

와우, 나는 누군가가 대답하고 얼마나 똑같은 짓을했는지 놀랍다! 나는 이것이 불가능하다고 생각했다. 나는 인증서를 얻는 방법을 보여주기 위해 내 게시물을 편집했습니다. 이것은 믿을 수있는 온라인에서 찾은 함수이므로 콜백을 수정하여 true를 반환했습니다. 너가 말하는게 이거니? 나는 여전히 단지 1 개의 사슬 요소만을 가지고있다. 감사! – Tor

+0

글쎄, 내가 TcpClient에 익숙하지 않은데, 나는 HttpWebClient와 함께했다. 그래도 인증서 체인을 얻는 것이 큰 차이는 아니라고 생각합니다. 솔직하게, 나는 인증서 자체를 검사 할 것이다. 호스트에 바인드 된 인증서가 루트/중간 인증서가 연결된 유효하고 서명 된 인증서인지 또는 루트 인증서가 잘못 바인딩되어 있는지 확인할 수 있습니까? – mppowe

+0

Chrome에서 검사했을 때 인증서 자체가 문제가되지 않으며 중급 CA가 있고 그 위에 루트가있는 경우 – Tor