2013-06-10 50 views
6

Tôi đang gặp khó khăn với vấn đề chứng chỉ ứng dụng khách và hy vọng ai đó ở đây có thể giúp tôi. Tôi đang phát triển một cặp máy khách/máy chủ bằng cách sử dụng asio tăng nhưng tôi sẽ cố gắng không cụ thể. Tôi đang sử dụng các cửa sổ và sử dụng openssl 1.0.1eỨng dụng khách OpenSSL không gửi chứng chỉ ứng dụng khách

Về cơ bản, tôi muốn có xác thực ứng dụng khách bằng cách sử dụng chứng chỉ ứng dụng khách. Máy chủ sẽ chỉ chấp nhận các máy khách có chứng chỉ được ký bởi CA của riêng tôi. Vì vậy, tôi đã thiết lập một CA tự ký. Điều này đã phát hành thêm hai chứng chỉ. Một cho khách hàng và một cho máy chủ. Cả hai được ký bởi CA. Tôi đã làm điều đó khá nhiều lần và tôi tự tin rằng tôi đã nhận được nó.

Phía máy chủ của tôi cũng hoạt động tốt. Nó yêu cầu chứng chỉ ứng dụng khách và nếu tôi đang sử dụng s_client và cung cấp cho các chứng chỉ đó hoạt động. Ngoài ra nếu tôi đang sử dụng một trình duyệt và đã cài đặt CA gốc của tôi là đáng tin cậy và sau đó nhập các chứng chỉ ứng dụng khách.

Điều duy nhất mà tôi không thể làm việc là ứng dụng khách libssl. Nó luôn thất bại trong khi bắt tay và như xa như tôi có thể nhìn thấy nó sẽ không gửi các certficate khách hàng:

$ openssl.exe s_server -servername localhost -bugs -CAfile myca.crt -cert server.crt 
-cert2 server.crt -key private/server.key -key2 private/server.key -accept 8887 -www 
-state -Verify 5 
verify depth is 5, must return a certificate 
Setting secondary ctx parameters 
Using default temp DH parameters 
Using default temp ECDH parameters 
ACCEPT 
SSL_accept:before/accept initialization 
SSL_accept:SSLv3 read client hello A 
SSL_accept:SSLv3 write server hello A 
SSL_accept:SSLv3 write certificate A 
SSL_accept:SSLv3 write key exchange A 
SSL_accept:SSLv3 write certificate request A 
SSL_accept:SSLv3 flush data 
SSL3 alert read:warning:no certificate 
SSL3 alert write:fatal:handshake failure 
SSL_accept:error in SSLv3 read client certificate B 
SSL_accept:error in SSLv3 read client certificate B 
2675716:error:140890C7:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:peer did not return a 
certificate:s3_srvr.c:3193: 
ACCEPT 

Tôi đang sử dụng s_server này như một công cụ gỡ lỗi nhưng đối với máy chủ thật của tôi điều tương tự xảy ra. s_client sẽ hoạt động tốt với cùng chứng chỉ. Ngoài ra, nếu tôi vô hiệu hóa "-Xác minh" trong máy chủ kết nối hoạt động. Vì vậy, nó thực sự có vẻ như chỉ là khách hàng từ chối gửi nó certficate. Điều gì có thể là lý do cho điều đó?

Kể từ khi tôi đang sử dụng tăng ASIO như một SSL bao bọc mã trông như thế này:

m_ssl_context.set_verify_mode(asio::ssl::context::verify_peer); 
m_ssl_context.load_verify_file("myca.crt"); 
m_ssl_context.use_certificate_file("testclient.crt", asio::ssl::context::pem); 
m_ssl_context.use_private_key_file("testclient.key", asio::ssl::context::pem); 

Tôi cũng đã cố gắng để vượt qua ASIO và truy cập vào bối cảnh SSL trực tiếp bằng cách nói:

SSL_CTX *ctx = m_ssl_context.impl(); 
SSL *ssl = m_ssl_socket.impl()->ssl; 
int res = 0; 
res = SSL_CTX_use_certificate_chain_file(ctx, "myca.crt"); 
if (res <= 0) { 
    // handle error 
} 
res = SSL_CTX_use_certificate_file(ctx, "testclient.crt", SSL_FILETYPE_PEM); 
if (res <= 0) { 
    // handle error 
} 
res = SSL_CTX_use_PrivateKey_file(ctx, "testclient.key", SSL_FILETYPE_PEM); 
if (res <= 0) { 
    // handle error 
} 

Tôi không thể thấy bất kỳ sự khác biệt nào về hành vi. Nó nên được đề cập rằng tôi đang sử dụng một asio rất cũ 1,43 asio mà tôi không thể cập nhật nhưng tôi cho rằng tất cả các cuộc gọi có liên quan đi nhiều hay ít trực tiếp đến OpenSSL và máy chủ hoạt động tốt với phiên bản đó nên tôi nghĩ rằng tôi có thể loại trừ.

Nếu tôi bắt đầu ép khách hàng và máy chủ đến các phiên bản cụ thể, thông báo lỗi thay đổi nhưng nó không bao giờ hoạt động và vẫn luôn hoạt động với kiểm tra s_client. Hiện nay nó được thiết lập để TLSv1

Nếu tôi chuyển nó đến TLSv1 ví dụ có nhiều trò chuyện giữa client và server và cuối cùng tôi nhận được lỗi:

... 
SSL_accept:SSLv3 read client key exchange A 
<<< TLS 1.0 ChangeCipherSpec [length 0001] 
    01 
<<< TLS 1.0 Handshake [length 0010], Finished 
    14 00 00 0c f4 71 28 4d ab e3 dd f2 46 e8 8b ed 
>>> TLS 1.0 Alert [length 0002], fatal unexpected_message 
    02 0a 
SSL3 alert write:fatal:unexpected_message 
SSL_accept:failed in SSLv3 read certificate verify B 
2675716:error:140880AE:SSL routines:SSL3_GET_CERT_VERIFY:missing verify 
message:s3_srvr.c:2951: 
2675716:error:140940E5:SSL routines:SSL3_READ_BYTES:ssl handshake failure:s3_pkt.c:989: 
ACCEPT 

Tôi đã tìm thấy một mục lỗi cũ đăng tải trên danh sách gửi thư openssl đã được quy định cho điều này. Rõ ràng là một CRLF sai trong cái bắt tay đã được sửa cách đây hai năm. Hay có nó?

Tôi đã gỡ lỗi này trong gần một tuần và tôi thực sự bị kẹt. Có ai có một gợi ý về những gì để thử? Tôi ra khỏi ý tưởng ...

Chúc mừng, Stephan

PS: Đây là những gì các s_server debug ra ở trên sẽ là với s_client và certficate cùng:

$ openssl s_client -CAfile ca.crt -cert testclient.crt -key private/testclient.key -verify 2 -connect myhost:8887 

ACCEPT 
SSL_accept:before/accept initialization 
SSL_accept:SSLv3 read client hello A 
SSL_accept:SSLv3 write server hello A 
SSL_accept:SSLv3 write certificate A 
SSL_accept:SSLv3 write key exchange A 
SSL_accept:SSLv3 write certificate request A 
SSL_accept:SSLv3 flush data 
depth=1 C = DE, // further info 
verify return:1 
depth=0 C = DE, // further info 
verify return:1 
SSL_accept:SSLv3 read client certificate A 
SSL_accept:SSLv3 read client key exchange A 
SSL_accept:SSLv3 read certificate verify A 
SSL_accept:SSLv3 read finished A 
SSL_accept:SSLv3 write session ticket A 
SSL_accept:SSLv3 write change cipher spec A 
SSL_accept:SSLv3 write finished A 
SSL_accept:SSLv3 flush data 
ACCEPT 

... bắt tay hoàn thành và dữ liệu được chuyển giao.

Trả lời

2

Được rồi, sau nhiều đau khổ, câu trả lời đã được tìm thấy bởi Dave Thompson của OpenSSL.

Lý do là mã ssl của tôi được gọi là tất cả các hàm đó trên ngữ cảnh OpenSSL sau khi đối tượng socket (SSL *) được tạo ra từ nó. Điều đó có nghĩa là tất cả những chức năng đó thực tế không có gì hoặc là điều sai trái.

Tất cả tôi phải làm là một trong hai:

1. Gọi SSL_use_certificate_file

res = SSL_use_certificate_file(ssl, "testclient.crt", SSL_FILETYPE_PEM); 
if (res <= 0) { 
    // handle error 
} 
res = SSL_use_PrivateKey_file(ssl, "testclient.key", SSL_FILETYPE_PEM); 
if (res <= 0) { 
    // handle error 
} 

(chú ý đến thiếu CTX)

2. Gọi CTX chức năng

Gọi các chức năng CTX theo ngữ cảnh trước khi ổ cắm được tạo. Như asio dường như khuyến khích để tạo ra bối cảnh và ổ cắm ngay sau đó (như tôi đã làm trong danh sách initializer) các cuộc gọi là tất cả, nhưng vô dụng.

Ngữ cảnh SSL (trong lib OpenSSL hoặc asio giống nhau) đóng gói việc sử dụng SSL và mỗi socket được tạo từ nó sẽ chia sẻ các thuộc tính của nó.

Cảm ơn các bạn đã đề xuất.

1

Bạn không nên sử dụng cả SSL_CTX_use_certificate_chain_file() và SSL_CTX_use_certificate_file(), vì SSL_CTX_use_certificate_chain_file() cố tải chuỗi bao gồm chứng chỉ ứng dụng khách chứ không chỉ chuỗi CA. Từ SSL_CTX_use_certificate(3):

SSL_CTX_use_certificate_chain_file() loads a certificate chain from file into ctx. The certificates must be in PEM format and must be sorted starting with the subject's certificate (actual client or server certificate), followed by intermediate CA certificates if applicable, and ending at the highest level (root) CA.

Tôi nghĩ rằng bạn nên sử dụng tốt chỉ sử dụng SSL_CTX_use_certificate_file() và SSL_CTX_use_PrivateKey_file(), như khách hàng không quan tâm nhiều cho chuỗi CA anyway.

+0

Rất tiếc, tôi đã thử tất cả các kết hợp mà tôi có thể đưa ra. Bao gồm cái này. Không có kết quả. Có vẻ như khách hàng sẽ không tin tưởng vào chứng chỉ ứng dụng khách của chính mình và không gửi nó. Nếu tôi sử dụng kết hợp này, khách hàng sẽ không gửi chứng chỉ nào cả, Nếu tôi sử dụng tệp chuỗi, có vẻ như nó sẽ gửi CA gốc thay vì của riêng mình. –

+0

Nếu nó gửi CA gốc, đó là vì bạn đang gọi SSL_CTX_use_certificate_chain_file() chỉ với chứng chỉ CA trong đó. Bạn có thể thử truyền tệp chỉ chứa chứng chỉ ứng dụng khách của bạn tới SSL_CTX_use_certificate_chain_file() không? –

+0

Xin cảm ơn tất cả mọi người! Nhiều đánh giá cao! @Remi: khi tôi làm điều này, khách hàng không gửi bất kỳ chứng chỉ nào. Đó là trường hợp đầu tiên tôi đã mô tả. Mà bằng cách này cũng là trường hợp nếu tập tin chuỗi chỉ chứa các cert cert. Tôi biết, điều đó không hợp lý nhưng tôi vẫn muốn thử. –

1

Tôi nghĩ bạn cần gọi số SSL_CTX_set_client_CA_list ở phía máy chủ. Điều này đặt danh sách các tổ chức phát hành chứng chỉ được gửi cùng với yêu cầu chứng chỉ ứng dụng khách.

Khách hàng sẽ không gửi chứng chỉ, ngay cả khi một người được yêu cầu, nếu chứng chỉ không khớp với danh sách CA được máy chủ gửi.

+0

Có. Điều này đã được thực hiện. Và nó được gửi đi. Thật không may vấn đề của tôi là trên máy khách. Tôi sử dụng s_server openssl để gỡ lỗi khách hàng của riêng tôi. Vì vậy, máy chủ của riêng tôi không quan trọng ở đây. Chỉ cần giả sử nó là OK và tôi chỉ đơn giản là không thể kết nối với công cụ kiểm tra s_server.Mà tôi phải giả định nói chính xác giao thức của nó. –

+0

Xin lỗi, tôi đã bỏ qua điều đó. Tôi giả sử bạn đã kiểm tra các công cụ hoàn toàn rõ ràng như là tập tin quan trọng đúng không? Trong dòng lệnh s_client của bạn là private/testclient.key, trong mã nó chỉ là "testclient.key". Mã của tôi (làm việc) thực hiện chính xác những gì bạn làm trừ khi tôi thực hiện SSL_CTX_check_private_key để xác minh nó khớp với chứng chỉ và tôi cài đặt một cuộc gọi lại mật khẩu để "mở khóa" khóa riêng: SSL_CTX_set_default_passwd_cb. – Tannin

+0

Không phải lo lắng, Cảm ơn mọi đầu vào. Tôi hoàn toàn say mê ở đây. Đối với certs, than ôi, tôi đã làm. Kiểm tra chúng hơn và hơn, diffed các tập tin và như vậy. Lý do cho sự khác biệt dòng lệnh đó chỉ là tôi đã thay thế một tên bí mật 'nghi ngờ bí mật' bằng tên tôi có thể đăng ở đây ;-) Tôi chắc chắn chúng đúng. SSL_CTX_check_private_key trả về true. Gọi lại mật khẩu đó có cần thiết cho các khóa mật khẩu trống không? –

Các vấn đề liên quan