2016-10-24 8 views
1

Indy 및 OpenSSL을 사용하는 서버에서 TLS 루트 CA 인증서를 검색 할 수 있습니까? 나는 이미이 글을 (German) Delphi-Praxis http://www.delphipraxis.net/190534-indy-openssl-komplette-zertifikatskette-im-client-ermitteln.html 에 올렸지 만 대답이 없습니다.Indy 및 OpenSSL을 사용하여 TLS 루트 CA 인증서를 검색하는 방법

서버 인증서의 전체 인증서 체인을 검색하여 사용자에게 표시해야합니다. 아마도 대다수의 서버가 자체 서명 된 인증서 나 엔터프라이즈 내부 CA를 갖기 때문에 신뢰할 수있는 CA를 추가하지 않고 목록을 최신 상태로 유지하려고하지 않을 것입니다.

mail.startcom.org에 액세스 할 때 내 프로그램의 출력입니다. 나는 루트 CA ("/ C = IL/O = StartCom Ltd./OU=Secure 디지털 인증서 서명/CN = StartCom 인증 기관") 내가 사용

*** Got certificate. Depth = 1, Error = 20 
    Subject: /C=IL/O=StartCom Ltd./OU=StartCom Certification Authority/CN=StartCom Class 3 OV Server CA 
    Issuer: /C=IL/O=StartCom Ltd./OU=Secure Digital Certificate Signing/CN=StartCom Certification Authority 
    SHA1 Fingerprint: 5A:F7:D2:E0:80:5E:1C:7B:E5:74:22:F3:5E:63:6B:25:94:47:E5:D7 

*** Got certificate. Depth = 0, Error = 20 
    Subject: /C=IL/ST=HaDarom/L=Eilat/O=StartCom Ltd. (Start Commercial Limited)/CN=mail.startcom.org 
    Issuer: /C=IL/O=StartCom Ltd./OU=StartCom Certification Authority/CN=StartCom Class 3 OV Server CA 
    SHA1 Fingerprint: F2:65:56:CD:A7:41:73:D8:FE:B6:85:4F:D8:79:E4:BA:3F:4D:78:C7 
EIdConnClosedGracefully: Connection Closed Gracefully. 

목은 OpenSSL 버전이없는 내 출력에서 ​​생각 1.0.2j이고 indy 버전은 Delphi XE2에 번들 된 버전입니다. 10.1 베를린 (그리고 함께 번들 된 indy 버전)을 사용하여 응용 프로그램을 컴파일하면 동일한 동작을 볼 수 있습니다. 난 그냥 전화를 없거나이 인디/OpenSSL을에 문제가

unit Unit1; 

interface 

uses 
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, 
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, 

    IdSmtp, IdSSLOpenSSL, IdExplicitTLSClientServerBase; 

type 
    TForm1 = class(TForm) 
    btnGetCertChain: TButton; 
    Memo1: TMemo; 
    chkCancelTlsHandshake: TCheckBox; 
    editHost: TEdit; 
    editPort: TEdit; 
    procedure btnGetCertChainClick(Sender: TObject); 
    function TlsVerifyPeer(Certificate: TIdX509; 
    AOk: Boolean; ADepth, AError: Integer): Boolean; 
    procedure FormCreate(Sender: TObject); 
    procedure FormDestroy(Sender: TObject); 
    private 
    FSMTPClient: TIdSMTP; 
    procedure InitTls(); 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

procedure TForm1.btnGetCertChainClick(Sender: TObject); 
begin 
    memo1.Clear(); 
    Memo1.Lines.Add('Trying to connect to ' + editHost.Text + '.' + editPort.Text); 

    FSMTPClient.Host := editHost.Text;//'mail.startcom.org'; 
    FSmtpClient.Port := StrToIntDef(editPort.Text, -1);//25; 
    try 
    FSmtpClient.Connect(); 
    FSMTPClient.Authenticate(); // calls StartTLS 
    except 
    on E: Exception do 
    begin 
     // when we "cancel" the handshake, there will be an exception... 
     Memo1.Lines.Add(E.ClassName + ': ' + E.Message); 
    end; 
    end; 
    FSmtpClient.Disconnect(); 
end; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    FSMTPClient := TIdSMTP.Create(nil); 
    InitTls(); 
end; 

procedure TForm1.FormDestroy(Sender: TObject); 
begin 
    FreeAndNil(FSMTPClient); 
end; 

procedure TForm1.InitTls; 
var 
    SslIoHandler: TIdSSLIOHandlerSocketOpenSSL; 
begin 
    SslIoHandler := TIdSSLIOHandlerSocketOpenSSL.Create(FSMTPClient); 

    SslIoHandler.SSLOptions.Method := sslvTLSv1; 
    SslIoHandler.SSLOptions.VerifyMode := [sslvrfPeer]; 
    SslIoHandler.SSLOptions.VerifyDepth := 9; // 9 is default: https://linux.die.net/man/3/ssl_ctx_set_verify_depth 
// SslIoHandler.SSLOptions.RootCertFile ; // don't have one 
    SslIoHandler.OnVerifyPeer := TlsVerifyPeer; // Necessary for certificate verification 

    FSMTPClient.IOHandler := SslIoHandler; // ownership of SslIoHandler is moved 
    FSMTPClient.UseTLS := utUseRequireTLS; 
end; 

function TForm1.TlsVerifyPeer(Certificate: TIdX509; AOk: Boolean; ADepth, 
    AError: Integer): Boolean; 
begin 
// store/output certificate info... or just output for demonstrational purpose 
Memo1.Lines.Add(''); 
    Memo1.Lines.Add('*** Got certificate. Depth = ' + inttostr(ADepth)+', Error = ' + IntToStr(AError)); 
    Memo1.Lines.Add(' Subject: ' + Certificate.Subject.OneLine); 
    Memo1.Lines.Add(' Issuer: ' + Certificate.Issuer.OneLine); 
    Memo1.Lines.Add(' SHA1 Fingerprint: ' + Certificate.Fingerprints.SHA1AsString); 

    result := true; 
    if chkCancelTlsHandshake.Checked then 
    begin 
    // for now we do not want to continue - present certificates to the user first 
    result := ADepth > 0; // false for leaf cert; true for (intermediate) CAs 
    end; 
end; 

end. 

암 : 여기

내 샘플 응용 프로그램의 코드?

답변

1

은 가능한 인디 사용하여 서버에서 TLS 루트 CA 인증서를 검색하는 것입니다 및 OpenSSL을

PKIX에 대한 짧은 대답, 그것은 의존한다. PKIX is the Internet's PKI 그리고 그것을 제어하는 ​​IETF 작업 그룹이 있습니다. 다른 PKI는 IETF가 PKIX를 실행하는 방식과 다르게 실행될 수 있습니다.

잘 구성된 서버에서 서버는 최종 엔티티 인증서와 필요한 모든 중간 CA 인증서를 build a path for validation으로 보냅니다. 서버는 PKI의 which directory problem을 해결하기 위해 중간 물을 전송합니다. 클라이언트가 이미 가지고 있기 때문에 서버는 루트 CA를 보내지 않습니다.

많은 서버가 루트 CA도 보내 게됩니다. 클라이언트는 대역 외를 가져 와서 이미 신뢰해야하기 때문에 일반적으로 의미가 없습니다. 클라이언트가 루트를 가지고 있지 않다면 나쁜 사람은 단순히 루트와 체인을 바꿀 수 있습니다.


은 mail.startcom.org 접근 내 프로그램의 출력입니다. 나는 수가 없습니다 루트 CA가없는 내 출력 ("/ C = IL/O = StartCom Ltd./OU=Secure 디지털 인증서 서명/CN = StartCom 인증 기관")

생각 연결 :

$ openssl s_client -starttls smtp -connect mail.startcom.org:25 -servername mail.startcom.org -tls1 
140735103578496:error:0200203C:system library:connect:Operation timed out:crypto/bio/b_sock2.c:108: 
140735103578496:error:2008A067:BIO routines:BIO_connect:connect error:crypto/bio/b_sock2.c:109: 
connect:errno=60 

과 :

$ openssl s_client -connect mail.startcom.org:465 -servername mail.startcom.org -tls1 
CONNECTED(00000003) 
140735103578496:error:1408F10B:SSL routines:ssl3_get_record:wrong version number:ssl/record/ssl3_record.c:250: 
... 

StartCom가 SMTPS를 통해 이메일로 구성 문제가 나타납니다. 어쩌면 그것은 당신의 문제의 원천 일 것입니다. TLS 포트를 통해 일반 텍스트 메일을 실행하고있는 것 같습니다.아래의 반응을 주목하라 -는 일반 텍스트 메일 명령 당신이 일을 s_client을 얻을 수있는 경우

$ openssl s_client -connect mail.startcom.org:465 -servername mail.startcom.org -tls1 -debug 
CONNECTED(00000003) 
write to 0x7f8d1241fd70 [0x7f8d12821600] (128 bytes => 128 (0x80)) 
0000 - 16 03 01 00 7b 01 00 00-77 03 01 cc f5 46 b3 e3 ....{...w....F.. 
0010 - ef 84 0b b4 ca 05 7a 6b-e7 6f 9b d7 15 aa 80 c3 ......zk.o...... 
0020 - e5 4f 3d a5 76 56 1d 63-dc c1 3d 00 00 12 c0 0a .O=.vV.c..=..... 
0030 - c0 14 00 39 c0 09 c0 13-00 33 00 35 00 2f 00 ff ...9.....3.5./.. 
0040 - 01 00 00 3c 00 00 00 16-00 14 00 00 11 6d 61 69 ...<.........mai 
0050 - 6c 2e 73 74 61 72 74 63-6f 6d 2e 6f 72 67 00 0b l.startcom.org.. 
0060 - 00 04 03 00 01 02 00 0a-00 0a 00 08 00 1d 00 17 ................ 
0070 - 00 19 00 18 00 23 00 00-00 16 00 00 00 17   .....#........ 
0080 - <SPACES/NULS> 
read from 0x7f8d1241fd70 [0x7f8d12819203] (5 bytes => 5 (0x5)) 
0000 - 32 32 30 20 6d         220 m 

이, 그것은 당신을 당신이 사용해야하는 루트 인증서 말할 것이다. 마지막 체인 인쇄물의 발급자가됩니다 (예 : “verify error:num=20” when connecting to gateway.sandbox.push.apple.com 참조).

루트 인증서의 고유 이름을 알고 있으면 SSL_load_verify_locations을 통해 OpenSSL에서 사용합니다. 나는 델파이에서 그것을하는 방법을 지금하지 않는다.

그런데 보통 서버 이름 표시을 사용해야합니다. OpenSSL에서는 SSL_set_tlsext_host_name을 사용합니다. 나는 델파이에서 그것을하는 방법을 지금하지 않는다. 루트 인증서의 고유 이름을 알게되면


, 당신은 SSL_load_verify_locations를 통해 OpenSSL을에서 사용 . 나는 이제 어떻게해야합니까? 델파이에서 해보십시오.

그런데 Certificates and Public Key Infrastructure 페이지에서 StartCom 인증서를 다운로드 할 수 있습니다.

관련 문제