From 45018b4f872c03c48414d24f4a9ecaec27393889 Mon Sep 17 00:00:00 2001 From: Andreas Sigfridsson <sigge@lysator.liu.se> Date: Sun, 22 Oct 2000 13:35:14 +0200 Subject: [PATCH] Added SSL client certificate support. Rev: lib/modules/SSL.pmod/DOC:1.2 Rev: lib/modules/SSL.pmod/connection.pike:1.14 Rev: lib/modules/SSL.pmod/context.pike:1.12 Rev: lib/modules/SSL.pmod/handshake.pike:1.21 Rev: lib/modules/SSL.pmod/session.pike:1.12 Rev: lib/modules/SSL.pmod/sslfile.pike:1.25 Rev: lib/modules/SSL.pmod/sslport.pike:1.7 --- lib/modules/SSL.pmod/DOC | 17 +++-- lib/modules/SSL.pmod/connection.pike | 4 +- lib/modules/SSL.pmod/context.pike | 7 +- lib/modules/SSL.pmod/handshake.pike | 97 ++++++++++++++++++++-------- lib/modules/SSL.pmod/session.pike | 6 +- lib/modules/SSL.pmod/sslfile.pike | 13 +++- lib/modules/SSL.pmod/sslport.pike | 1 + 7 files changed, 100 insertions(+), 45 deletions(-) diff --git a/lib/modules/SSL.pmod/DOC b/lib/modules/SSL.pmod/DOC index f53a447223..45b55b93ad 100644 --- a/lib/modules/SSL.pmod/DOC +++ b/lib/modules/SSL.pmod/DOC @@ -145,11 +145,6 @@ SSL.session (inherits cipher) SSL.context - int auth_level - - Policy for client authentication. One of AUTHLEVEL_none, - AUTHLEVEL_ask and AUTHLEVEL_require. - object rsa The server's private key @@ -181,7 +176,6 @@ SSL.context The server's certificate, or a chain of certificates, with the server's certificate first and root certificate last. - array(string) authorities array(int) preferred_auth_methods For client authentication. Used only if auth_level is AUTH_ask or @@ -231,6 +225,17 @@ SSL.context SSL.handshake + int auth_level + + Policy for client authentication. One of AUTHLEVEL_none, + AUTHLEVEL_ask and AUTHLEVEL_require. + + array(string) authorities + + Array of authorities that are accepted for client certificates. + The client will only send certificates that are signed by any of + these authorities. The string is the DER-encoded issuer. + object session object context diff --git a/lib/modules/SSL.pmod/connection.pike b/lib/modules/SSL.pmod/connection.pike index e45f44698b..c5137ded5c 100644 --- a/lib/modules/SSL.pmod/connection.pike +++ b/lib/modules/SSL.pmod/connection.pike @@ -1,4 +1,4 @@ -/* $Id: connection.pike,v 1.13 2000/08/04 19:07:11 sigge Exp $ +/* $Id: connection.pike,v 1.14 2000/10/22 11:35:13 sigge Exp $ * * SSL packet layer */ @@ -176,7 +176,7 @@ int handle_alert(string s) } if (description == ALERT_no_certificate) { - if ((certificate_state == CERT_requested) && (context->auth_level == AUTHLEVEL_ask)) + if ((certificate_state == CERT_requested) && (auth_level == AUTHLEVEL_ask)) { certificate_state = CERT_no_certificate; return 0; diff --git a/lib/modules/SSL.pmod/context.pike b/lib/modules/SSL.pmod/context.pike index eec99d2182..2f05e5baf8 100644 --- a/lib/modules/SSL.pmod/context.pike +++ b/lib/modules/SSL.pmod/context.pike @@ -1,4 +1,4 @@ -/* $Id: context.pike,v 1.11 2000/08/04 19:08:07 sigge Exp $ +/* $Id: context.pike,v 1.12 2000/10/22 11:35:13 sigge Exp $ * * Keeps track of global data for an SSL server, * such as preferred encryption algorithms and session cache. @@ -6,8 +6,6 @@ inherit "constants"; -int auth_level; - object rsa; /* Servers private key */ /* These temporary keys, of non-zero, are used for the @@ -24,9 +22,6 @@ function(int:string) random; /* Random number generator */ * Senders certificate first, root certificate last .*/ array(string) certificates; -/* For client authentication */ -array(string) authorities; /* List of authorities distinguished names */ - array(int) preferred_auth_methods = ({ AUTH_rsa_sign }); diff --git a/lib/modules/SSL.pmod/handshake.pike b/lib/modules/SSL.pmod/handshake.pike index a5f798d59c..0d224b0db1 100644 --- a/lib/modules/SSL.pmod/handshake.pike +++ b/lib/modules/SSL.pmod/handshake.pike @@ -1,4 +1,4 @@ -/* $Id: handshake.pike,v 1.20 2000/09/05 15:06:40 per Exp $ +/* $Id: handshake.pike,v 1.21 2000/10/22 11:35:13 sigge Exp $ * */ @@ -12,6 +12,11 @@ inherit "cipher"; #define SSL3_DEBUG_MSG #endif /* SSL3_DEBUG */ +/* For client authentication */ +int auth_level; // Wether to ask or require a client certificate +array(string) authorities; // List of authorities accepted for client + // certificates (DER-encoded) + object session; object context; @@ -72,6 +77,11 @@ object handshake_packet(int type, string data) return packet; } +object hello_request() +{ + return handshake_packet(HANDSHAKE_hello_request, ""); +} + object server_hello_packet() { object struct = Struct(); @@ -255,15 +265,15 @@ int reply_new_session(array(int) cipher_suites, array(int) compression_methods) if (key_exchange) send_packet(key_exchange); - if (context->auth_level >= AUTHLEVEL_ask) + if (auth_level >= AUTHLEVEL_ask) { /* Send a CertificateRequest message */ object struct = Struct(); struct->put_var_uint_array(context->preferred_auth_methods, 1, 1); - int len = `+(@ Array.map(context->authorities, strlen)); - struct->put_uint(len + 2 * sizeof(context->authorities), 2); - foreach(context->authorities, string auth) + int len = `+(@ Array.map(authorities, strlen)); + struct->put_uint(len + 2 * sizeof(authorities), 2); + foreach(authorities, string auth) struct->put_var_string(auth, 2); send_packet(handshake_packet(HANDSHAKE_certificate_request, struct->pop_data())); @@ -334,7 +344,9 @@ string server_derive_master_secret(string data) dh_state->set_other(struct->get_bignum); } || !struct->is_empty()) { - send_packet(Alert(ALERT_fatal, ALERT_unexpected_message)); + send_packet(Alert(ALERT_fatal, ALERT_unexpected_message, + "SSL.session->handle_handshake: unexpected message\n", + backtrace())); return 0; } @@ -502,7 +514,9 @@ int handle_handshake(int type, string data, string raw) } || (version[0] != 3) || (cipher_len & 1)) { - send_packet(Alert(ALERT_fatal, ALERT_unexpected_message)); + send_packet(Alert(ALERT_fatal, ALERT_unexpected_message, + "SSL.session->handle_handshake: unexpected message\n", + backtrace())); return -1; } @@ -574,7 +588,9 @@ int handle_handshake(int type, string data, string raw) werror(sprintf("SSL.handshake: Error decoding SSL2 handshake:\n" "%s\n", describe_backtrace(err))); #endif /* SSL3_DEBUG */ - send_packet(Alert(ALERT_fatal, ALERT_unexpected_message)); + send_packet(Alert(ALERT_fatal, ALERT_unexpected_message, + "SSL.session->handle_handshake: unexpected message\n", + backtrace())); return -1; } @@ -590,15 +606,19 @@ int handle_handshake(int type, string data, string raw) challenge = input->get_fix_string(ch_len); } || !input->is_empty()) { - send_packet(Alert(ALERT_fatal, ALERT_unexpected_message)); + send_packet(Alert(ALERT_fatal, ALERT_unexpected_message, + "SSL.session->handle_handshake: unexpected message\n", + backtrace())); return -1; } client_random = ("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + challenge)[..31]; - err = reply_new_session(cipher_suites, ({ COMPRESSION_null }) ); - if (err) - return err; + { + int err = reply_new_session(cipher_suites, ({ COMPRESSION_null }) ); + if (err) + return err; + } handshake_state = STATE_server_wait_for_client; - + break; } } @@ -620,7 +640,9 @@ int handle_handshake(int type, string data, string raw) digest = input->get_fix_string(36); } || !input->is_empty()) { - send_packet(Alert(ALERT_fatal, ALERT_unexpected_message)); + send_packet(Alert(ALERT_fatal, ALERT_unexpected_message, + "SSL.session->handle_handshake: unexpected message\n", + backtrace())); return -1; } if (rsa_message_was_bad /* Error delayed until now */ @@ -630,7 +652,9 @@ int handle_handshake(int type, string data, string raw) SSL3_DEBUG_MSG("rsa_message_was_bad\n"); if(my_digest != digest) SSL3_DEBUG_MSG("digests differ\n"); - send_packet(Alert(ALERT_fatal, ALERT_unexpected_message)); + send_packet(Alert(ALERT_fatal, ALERT_unexpected_message, + "SSL.session->handle_handshake: unexpected message\n", + backtrace())); return -1; } handshake_messages += raw; /* Second hash includes this message, @@ -692,11 +716,11 @@ int handle_handshake(int type, string data, string raw) } else handshake_state = STATE_server_wait_for_verify; - + break; case HANDSHAKE_certificate: { - if (certificate_state == CERT_requested) //FIXME: huh? + if (certificate_state != CERT_requested) { send_packet(Alert(ALERT_fatal, ALERT_unexpected_message, "SSL.session->handle_handshake: unexpected message\n", @@ -704,7 +728,11 @@ int handle_handshake(int type, string data, string raw) return -1; } if (catch { - session->client_certificate = input->get_var_string(3); + int certs_len = input->get_uint(3); + array certs = ({ }); + while(!input->is_empty()) + certs += ({ input->get_var_string(3) }); + session->client_certificate_chain = certs; } || !input->is_empty()) { send_packet(Alert(ALERT_fatal, ALERT_unexpected_message, @@ -718,7 +746,8 @@ int handle_handshake(int type, string data, string raw) } break; case STATE_server_wait_for_verify: - handshake_messages += raw; + // handshake_messages += raw; + // compute challenge first, then update handshake_messages /Sigge switch(type) { default: @@ -729,10 +758,26 @@ int handle_handshake(int type, string data, string raw) case HANDSHAKE_certificate_verify: if (!rsa_message_was_bad) { - session->client_challenge = - mac_md5(session->master_secret)->hash_master(handshake_messages) + - mac_sha(session->master_secret)->hash_master(handshake_messages); - session->client_signature = data; + int verification_ok; + if( catch + { + object(Gmp.mpz) signature = input->get_bignum(); + Struct handshake_messages_struct = Struct(); + handshake_messages_struct->put_fix_string(handshake_messages); + verification_ok = session->cipher_spec->verify( + context, "", handshake_messages_struct, signature); + } || verification_ok) + { + send_packet(Alert(ALERT_fatal, ALERT_unexpected_message, + "SSL.session->handle_handshake: verification of" + " CertificateVerify message failed\n", + backtrace())); + return -1; + } +// session->client_challenge = +// mac_md5(session->master_secret)->hash_master(handshake_messages) + +// mac_sha(session->master_secret)->hash_master(handshake_messages); +// session->client_signature = data; } handshake_messages += raw; handshake_state = STATE_server_wait_for_finish; @@ -804,15 +849,14 @@ int handle_handshake(int type, string data, string raw) SSL3_DEBUG_MSG("Handshake: Certificate message recieved\n"); int certs_len = input->get_uint(3); array certs = ({ }); - int i=0; while(!input->is_empty()) certs += ({ input->get_var_string(3) }); - session->server_certificate = certs[0]; + session->server_certificate_chain = certs; if (catch { object public_key = Tools.X509.decode_certificate( - session->server_certificate)->public_key; + session->server_certificate_chain[0])->public_key; if(public_key->type == "rsa") { object rsa = Crypto.rsa(); @@ -940,6 +984,7 @@ int handle_handshake(int type, string data, string raw) void create(int is_server) { + auth_level = context->auth_level; if (is_server) handshake_state = STATE_server_wait_for_hello; else diff --git a/lib/modules/SSL.pmod/session.pike b/lib/modules/SSL.pmod/session.pike index 76843c4dcf..2455bc254c 100644 --- a/lib/modules/SSL.pmod/session.pike +++ b/lib/modules/SSL.pmod/session.pike @@ -1,4 +1,4 @@ -/* $Id: session.pike,v 1.11 2000/08/04 19:07:11 sigge Exp $ +/* $Id: session.pike,v 1.12 2000/10/22 11:35:13 sigge Exp $ * */ @@ -16,8 +16,8 @@ string master_secret; /* 48 byte secret shared between client and server */ constant Struct = ADT.struct; constant State = SSL.state; -string client_certificate; -string server_certificate; +array(string) client_certificate_chain; +array(string) server_certificate_chain; void set_cipher_suite(int suite) { diff --git a/lib/modules/SSL.pmod/sslfile.pike b/lib/modules/SSL.pmod/sslfile.pike index 88a8307739..a0a776c16a 100644 --- a/lib/modules/SSL.pmod/sslfile.pike +++ b/lib/modules/SSL.pmod/sslfile.pike @@ -1,4 +1,4 @@ -/* $Id: sslfile.pike,v 1.24 2000/08/15 21:35:43 mast Exp $ +/* $Id: sslfile.pike,v 1.25 2000/10/22 11:35:14 sigge Exp $ * */ @@ -139,7 +139,7 @@ int write(string|array(string) s) private void ssl_read_callback(mixed id, string s) { #ifdef SSL3_DEBUG - werror(sprintf("SSL.sslfile->ssl_read_callback\n")); + werror(sprintf("SSL.sslfile->ssl_read_callback, connected=%d, handshake_finished=%d\n", connected, handshake_finished)); #endif string|int data = got_data(s); if (stringp(data)) @@ -352,3 +352,12 @@ void create(object f, object c, int|void is_client) socket->set_nonblocking(ssl_read_callback, ssl_write_callback, ssl_close_callback); connection::create(!is_client); } + +void renegotiate() +{ + expect_change_cipher = certificate_state = 0; + send_packet(hello_request()); + socket->set_write_callback(ssl_write_callback); + handshake_finished = 0; + connected = 0; +} diff --git a/lib/modules/SSL.pmod/sslport.pike b/lib/modules/SSL.pmod/sslport.pike index 6c6b68400a..52a3497193 100644 --- a/lib/modules/SSL.pmod/sslport.pike +++ b/lib/modules/SSL.pmod/sslport.pike @@ -67,4 +67,5 @@ void create() #endif context::create(); accept_queue::create(); + set_id(this_object()); } -- GitLab