From 7aaa6349add1a1de05d8f8a3a8e01fce35b3f118 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Tue, 7 Aug 2001 13:34:50 +0000 Subject: [PATCH] server side client authentication works --- NEWS | 3 +- configure.in | 2 +- doc/tex/ex3.tex | 17 +++++----- doc/tex/serv1.tex | 5 ++- lib/auth_rsa.c | 38 +++++++++++++++++++++- lib/ext_srp.c | 9 +++++- lib/gnutls_auth_int.h | 1 + lib/gnutls_handshake.c | 11 ++++--- lib/gnutls_int.h | 5 +-- lib/gnutls_kx.c | 2 +- lib/gnutls_sig.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++- lib/gnutls_sig.h | 4 +-- lib/gnutls_ui.h | 10 ++++++ lib/x509_sig_check.c | 6 ++-- lib/x509_verify.c | 2 +- src/cli.c | 18 +++++------ src/serv.c | 46 +++++++++++++++++++++++++- 17 files changed, 229 insertions(+), 38 deletions(-) diff --git a/NEWS b/NEWS index 111a8f8cb..47c02ebe8 100644 --- a/NEWS +++ b/NEWS @@ -1,8 +1,9 @@ -Version 0.2.0 +Version 0.2.0 (07/08/2001) - Partial support for X509v3 Certificate extensions. - Added Internal memory handlers - Removed gnutls_x509_set_cn() - Added X509 client authentication +- Several bug fixes and protocol fixes Version 0.1.9 (30/07/2001) - Corrected bug(s) in ChangeCipherSpec packet (fixes renegotiate) diff --git a/configure.in b/configure.in index ef6eedc90..f2c75f796 100644 --- a/configure.in +++ b/configure.in @@ -24,7 +24,7 @@ GNUTLS_MOST_RECENT_INTERFACE=$GNUTLS_MINOR_VERSION GNUTLS_CURRENT_INTERFACE_IMPLEMENTATION_NUMBER=$GNUTLS_MICRO_VERSION GNUTLS_OLDEST_INTERFACE=0 -AM_PATH_LIBGCRYPT(1.1.3,, +AM_PATH_LIBGCRYPT(1.1.4,, AC_MSG_ERROR([[ *** *** libgcrypt was not found. You may want to get it from diff --git a/doc/tex/ex3.tex b/doc/tex/ex3.tex index 6eec57ddc..6aca20fbb 100644 --- a/doc/tex/ex3.tex +++ b/doc/tex/ex3.tex @@ -41,17 +41,16 @@ int print_info(GNUTLS_STATE state) break; } - } - printf(" - Certificate info:\n"); - printf(" - Certificate version: #%d\n", gnutls_x509pki_client_get_peer_certificate_version(x509_info)); - - dn = gnutls_x509pki_client_get_peer_dn( x509_info); - PRINT_DN(dn); + printf(" - Certificate info:\n"); + printf(" - Certificate version: #%d\n", gnutls_x509pki_client_get_peer_certificate_version(x509_info)); - printf(" - Certificate Issuer's info:\n"); - dn = gnutls_x509pki_client_get_issuer_dn( x509_info); - PRINT_DN(dn); + dn = gnutls_x509pki_client_get_peer_dn( x509_info); + PRINT_DN(dn); + printf(" - Certificate Issuer's info:\n"); + dn = gnutls_x509pki_client_get_issuer_dn( x509_info); + PRINT_DN(dn); + } } tmp = gnutls_version_get_name(gnutls_get_current_version(state)); diff --git a/doc/tex/serv1.tex b/doc/tex/serv1.tex index 0cbdd96f5..78cd49ca4 100644 --- a/doc/tex/serv1.tex +++ b/doc/tex/serv1.tex @@ -54,7 +54,10 @@ GNUTLS_STATE initialize_state() gnutls_set_cred(state, GNUTLS_SRP, srp_cred); gnutls_set_cred(state, GNUTLS_X509PKI, x509_cred); - + /* request client certificate if any. + */ + gnutls_set_certificate_request( state, GNUTLS_CERT_REQUEST); + return state; } diff --git a/lib/auth_rsa.c b/lib/auth_rsa.c index d5876d42b..d92ee1d22 100644 --- a/lib/auth_rsa.c +++ b/lib/auth_rsa.c @@ -527,6 +527,9 @@ int proc_rsa_server_certificate(GNUTLS_STATE state, opaque * data, int data_size verify = gnutls_verify_certificate(peer_certificate_list, peer_certificate_list_size, cred->ca_list, cred->ncas, NULL, 0); + /* keep the PK algorithm */ + state->gnutls_internals.peer_pk_algorithm = peer_certificate_list[0].subject_pk_algorithm; + _gnutls_copy_x509_client_auth_info(info, &peer_certificate_list[0], verify); /* This works for the client @@ -819,8 +822,41 @@ int gen_rsa_client_cert_vrfy(GNUTLS_STATE state, opaque ** data) int proc_rsa_client_cert_vrfy(GNUTLS_STATE state, opaque * data, int data_size) { - #warning "CHECK THE CERT VERIFY MESSAGE" +int size, ret; +int dsize = data_size; +opaque* pdata = data; +gnutls_cert cert; +gnutls_datum sig; + + DECR_LEN(dsize, 2); + size = READuint16( pdata); + pdata += 2; + + if ( size < data_size - 2) { + gnutls_assert(); + return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + + sig.data = pdata; + sig.size = size; + cert.params = gnutls_malloc( 2*sizeof(MPI)); + if (cert.params==NULL) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + cert.params[0] = state->gnutls_key->x; + cert.params[1] = state->gnutls_key->a; + cert.subject_pk_algorithm = state->gnutls_internals.peer_pk_algorithm; + + if ( (ret=_gnutls_verify_sig( state, &cert, &sig, data_size+HANDSHAKE_HEADER_SIZE))<0) { + gnutls_assert(); + gnutls_free( cert.params); + return ret; + } + + gnutls_free( cert.params); + return 0; } diff --git a/lib/ext_srp.c b/lib/ext_srp.c index 887bfbbf5..d4476b19d 100644 --- a/lib/ext_srp.c +++ b/lib/ext_srp.c @@ -35,8 +35,15 @@ int _gnutls_srp_recv_params( GNUTLS_STATE state, const opaque* data, int data_si } if (state->security_parameters.entity == GNUTLS_SERVER) { + /* algorithm was not selected + */ + if ( gnutls_get_auth_info_type( state) != GNUTLS_SRP) + return 0; + if (data_size > 0) { - state->gnutls_key->auth_info = gnutls_calloc(1, sizeof(SRP_SERVER_AUTH_INFO)); + if ( state->gnutls_key->auth_info == NULL) + state->gnutls_key->auth_info = gnutls_calloc(1, sizeof(SRP_SERVER_AUTH_INFO)); + if (state->gnutls_key->auth_info==NULL) return GNUTLS_E_MEMORY_ERROR; if (sizeof( ((SRP_SERVER_AUTH_INFO)state->gnutls_key->auth_info)->username) > data_size) { diff --git a/lib/gnutls_auth_int.h b/lib/gnutls_auth_int.h index 1deb4da09..6885edeb9 100644 --- a/lib/gnutls_auth_int.h +++ b/lib/gnutls_auth_int.h @@ -3,3 +3,4 @@ int gnutls_set_cred( GNUTLS_STATE state, CredType type, void* cred); const void *_gnutls_get_cred( GNUTLS_KEY key, CredType kx, int* err); const void *_gnutls_get_kx_cred( GNUTLS_KEY key, KXAlgorithm algo, int *err); int _gnutls_generate_key(GNUTLS_KEY key); +CredType gnutls_get_auth_info_type( GNUTLS_STATE); diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c index 2f425202f..307c74028 100644 --- a/lib/gnutls_handshake.c +++ b/lib/gnutls_handshake.c @@ -725,7 +725,10 @@ int _gnutls_recv_handshake(SOCKET cd, GNUTLS_STATE state, uint8 ** data, if (length32 > 0) dataptr = gnutls_malloc(length32); else -fprintf(stderr, "recv_type: %d\nLenght: %d\n", recv_type, length32); + if (recv_type != GNUTLS_SERVER_HELLO_DONE) { + gnutls_assert(); + return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } if (dataptr == NULL) { gnutls_assert(); @@ -781,9 +784,9 @@ fprintf(stderr, "recv_type: %d\nLenght: %d\n", recv_type, length32); ret = length32; break; case GNUTLS_CERTIFICATE_REQUEST: -#ifdef HANDSHAKE_DEBUG - _gnutls_log("Requested Client Certificate!\n"); -#endif + ret = length32; + break; + case GNUTLS_CERTIFICATE_VERIFY: ret = length32; break; default: diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 315078cec..c3960eb33 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -30,9 +30,9 @@ #define BUFFERS_DEBUG #define HARD_DEBUG #define RECORD_DEBUG -#define HANDSHAKE_DEBUG*/ +#define HANDSHAKE_DEBUG #define DEBUG - +*/ #define SOCKET int #define LIST ... @@ -348,6 +348,7 @@ typedef struct { * supports it. */ int send_cert_req; + int peer_pk_algorithm; } GNUTLS_INTERNALS; struct GNUTLS_STATE_INT { diff --git a/lib/gnutls_kx.c b/lib/gnutls_kx.c index 49786440d..24ad5376b 100644 --- a/lib/gnutls_kx.c +++ b/lib/gnutls_kx.c @@ -640,7 +640,7 @@ int _gnutls_recv_client_certificate_verify_message(SOCKET cd, GNUTLS_STATE state ret = _gnutls_recv_handshake(cd, state, &data, &datasize, - GNUTLS_CLIENT_KEY_EXCHANGE, OPTIONAL_PACKET); + GNUTLS_CERTIFICATE_VERIFY, OPTIONAL_PACKET); if (ret < 0) return ret; diff --git a/lib/gnutls_sig.c b/lib/gnutls_sig.c index ee206008d..9005f51b8 100644 --- a/lib/gnutls_sig.c +++ b/lib/gnutls_sig.c @@ -88,7 +88,6 @@ int ret; } - int _gnutls_pkcs1_rsa_generate_sig( gnutls_private_key *pkey, const gnutls_datum *data, gnutls_datum *signature) { int ret; @@ -100,3 +99,90 @@ int _gnutls_pkcs1_rsa_generate_sig( gnutls_private_key *pkey, const gnutls_datum return 0; } + +int _gnutls_pkcs1_rsa_verify_sig( gnutls_cert *cert, const gnutls_datum *data, gnutls_datum *signature) { + int ret; + gnutls_datum plain; + + /* decrypt signature */ + if ( (ret=_gnutls_pkcs1_rsa_decrypt( &plain, *signature, cert->params[0], cert->params[1], 1)) < 0) { + gnutls_assert(); + return ret; + } + + if (plain.size != data->size) { + gnutls_assert(); + return GNUTLS_E_PK_SIGNATURE_FAILED; + } + + if ( memcmp(plain.data, data->data, plain.size)!=0) { + gnutls_assert(); + return GNUTLS_E_PK_SIGNATURE_FAILED; + } + + return 0; +} + + +/* Verifies a TLS signature (like the one in the client certificate + * verify message). + */ +int _gnutls_verify_sig( GNUTLS_STATE state, gnutls_cert *cert, gnutls_datum* signature, int ubuffer_size) { +opaque digest[20+16]; +gnutls_datum data; +GNUTLS_HASH_HANDLE td; +int size = gnutls_getHashDataBufferSize( state) - ubuffer_size; /* do not get the last message */ +int ret; + + data.data = gnutls_malloc(size); + data.size = size; + if (data.data==NULL) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + gnutls_readHashDataFromBuffer( state, data.data, data.size); + + switch(cert->subject_pk_algorithm) { + case GNUTLS_PK_RSA: + + td = gnutls_hash_init( GNUTLS_MAC_MD5); + if (td==NULL) { + gnutls_assert(); + gnutls_free_datum( &data); + return GNUTLS_E_MEMORY_ERROR; + } + gnutls_hash( td, data.data, data.size); + gnutls_hash_deinit( td, digest); + + td = gnutls_hash_init( GNUTLS_MAC_SHA); + if (td==NULL) { + gnutls_assert(); + gnutls_free_datum( &data); + return GNUTLS_E_MEMORY_ERROR; + } + gnutls_hash( td, data.data, data.size); + gnutls_hash_deinit( td, &digest[16]); + gnutls_free_datum( &data); + + + data.data = digest; + data.size = 20+16; /* md5 + sha */ + ret = _gnutls_pkcs1_rsa_verify_sig( cert, &data, signature); + + break; + default: + gnutls_assert(); + gnutls_free_datum( &data); + ret = GNUTLS_E_UNIMPLEMENTED_FEATURE; + break; + } + + return ret; + +} + + + + + diff --git a/lib/gnutls_sig.h b/lib/gnutls_sig.h index 03ee658cd..95725c222 100644 --- a/lib/gnutls_sig.h +++ b/lib/gnutls_sig.h @@ -1,4 +1,4 @@ -int _gnutls_pkcs1_rsa_verify_sig( gnutls_datum* signature, gnutls_datum *text, MPI m, MPI e); -CertificateStatus gnutls_verify_signature(gnutls_cert* cert, gnutls_cert* issuer); +CertificateStatus gnutls_x509_verify_signature(gnutls_cert* cert, gnutls_cert* issuer); int _gnutls_pkcs1_rsa_generate_sig( gnutls_private_key *pkey, const gnutls_datum *data, gnutls_datum *signature); int _gnutls_generate_sig( GNUTLS_STATE state, gnutls_private_key *pkey, gnutls_datum *signature); +int _gnutls_verify_sig( GNUTLS_STATE state, gnutls_cert *cert, gnutls_datum* signature, int ubuffer_size); diff --git a/lib/gnutls_ui.h b/lib/gnutls_ui.h index ac8968f51..a87bc0485 100644 --- a/lib/gnutls_ui.h +++ b/lib/gnutls_ui.h @@ -59,6 +59,16 @@ time_t gnutls_x509pki_client_get_peer_certificate_activation_time( X509PKI_CLIE time_t gnutls_x509pki_client_get_peer_certificate_expiration_time( X509PKI_CLIENT_AUTH_INFO info); unsigned char gnutls_x509pki_client_get_key_usage( X509PKI_CLIENT_AUTH_INFO info); const char* gnutls_x509pki_client_get_subject_alt_name( X509PKI_CLIENT_AUTH_INFO info); + +#define gnutls_x509pki_server_get_peer_dn gnutls_x509pki_client_get_peer_dn +#define gnutls_x509pki_server_get_issuer_dn gnutls_x509pki_client_get_issuer_dn +#define gnutls_x509pki_server_get_peer_certificate_status gnutls_x509pki_client_get_peer_certificate_status +#define gnutls_x509pki_server_get_peer_certificate_version gnutls_x509pki_client_get_peer_certificate_version +#define gnutls_x509pki_server_get_peer_certificate_activation_time gnutls_x509pki_client_get_peer_certificate_activation_time +#define gnutls_x509pki_server_get_peer_certificate_expiration_time gnutls_x509pki_client_get_peer_certificate_expiration_time +#define gnutls_x509pki_server_get_key_usage gnutls_x509pki_client_get_key_usage +#define gnutls_x509pki_server_get_subject_alt_name gnutls_x509pki_client_get_subject_alt_name + # endif /* LIBGNUTLS_VERSION */ #endif diff --git a/lib/x509_sig_check.c b/lib/x509_sig_check.c index bd3f09fbf..93df42435 100644 --- a/lib/x509_sig_check.c +++ b/lib/x509_sig_check.c @@ -144,7 +144,7 @@ int len; * e is public key */ int -_gnutls_pkcs1_rsa_verify_sig( gnutls_datum* signature, gnutls_datum* text, MPI e, MPI m) +_pkcs1_rsa_verify_sig( gnutls_datum* signature, gnutls_datum* text, MPI e, MPI m) { MACAlgorithm hash; int ret; @@ -187,7 +187,7 @@ _gnutls_pkcs1_rsa_verify_sig( gnutls_datum* signature, gnutls_datum* text, MPI e return 0; } -CertificateStatus gnutls_verify_signature(gnutls_cert* cert, gnutls_cert* issuer) { +CertificateStatus gnutls_x509_verify_signature(gnutls_cert* cert, gnutls_cert* issuer) { gnutls_datum signature; gnutls_datum* tbs; @@ -201,7 +201,7 @@ gnutls_datum* tbs; return GNUTLS_CERT_INVALID; } - if (_gnutls_pkcs1_rsa_verify_sig( &signature, tbs, issuer->params[1], issuer->params[0])!=0) { + if (_pkcs1_rsa_verify_sig( &signature, tbs, issuer->params[1], issuer->params[0])!=0) { gnutls_assert(); gnutls_free_datum( tbs); return GNUTLS_CERT_NOT_TRUSTED; diff --git a/lib/x509_verify.c b/lib/x509_verify.c index aa5a61c9c..1f1f3fb39 100644 --- a/lib/x509_verify.c +++ b/lib/x509_verify.c @@ -289,7 +289,7 @@ int gnutls_verify_certificate2(gnutls_cert * cert, gnutls_cert * trusted_cas, in return GNUTLS_CERT_NOT_TRUSTED; } - ret = gnutls_verify_signature(cert, issuer); + ret = gnutls_x509_verify_signature(cert, issuer); if (ret != GNUTLS_CERT_TRUSTED) return ret; diff --git a/src/cli.c b/src/cli.c index 185110de4..d3377609d 100644 --- a/src/cli.c +++ b/src/cli.c @@ -85,17 +85,17 @@ const gnutls_DN* dn; break; } - } - printf(" - Certificate info:\n"); - printf(" - Certificate version: #%d\n", gnutls_x509pki_client_get_peer_certificate_version(x509_info)); + printf(" - Certificate info:\n"); + printf(" - Certificate version: #%d\n", gnutls_x509pki_client_get_peer_certificate_version(x509_info)); - dn = gnutls_x509pki_client_get_peer_dn( x509_info); - PRINT_DN( dn); + dn = gnutls_x509pki_client_get_peer_dn( x509_info); + PRINT_DN( dn); - dn = gnutls_x509pki_client_get_issuer_dn( x509_info); - printf(" - Certificate Issuer's info:\n"); - PRINT_DN( dn); + dn = gnutls_x509pki_client_get_issuer_dn( x509_info); + printf(" - Certificate Issuer's info:\n"); + PRINT_DN( dn); + } } tmp = gnutls_version_get_name(gnutls_get_current_version(state)); @@ -146,7 +146,7 @@ int main(int argc, char** argv) /* X509 stuff */ - if (gnutls_allocate_x509_client_sc( &xcred, 1) < 0) { + if (gnutls_allocate_x509_client_sc( &xcred, 1) < 0) { /* space for 1 certificate */ fprintf(stderr, "memory error\n"); exit(1); } diff --git a/src/serv.c b/src/serv.c index ab9580335..721cc7c7b 100644 --- a/src/serv.c +++ b/src/serv.c @@ -105,18 +105,29 @@ GNUTLS_STATE initialize_state() gnutls_set_mac_priority(state, GNUTLS_MAC_SHA, GNUTLS_MAC_MD5, 0); - gnutls_set_certificate_request( state, GNUTLS_CERT_REQUIRE); + gnutls_set_certificate_request( state, GNUTLS_CERT_REQUEST); return state; } +#define PRINTX(x,y) if (y[0]!=0) printf(" - %s %s\n", x, y) +#define PRINT_DN(X) PRINTX( "CN:", X->common_name); \ + PRINTX( "OU:", X->organizational_unit_name); \ + PRINTX( "O:", X->organization); \ + PRINTX( "L:", X->locality_name); \ + PRINTX( "S:", X->state_or_province_name); \ + PRINTX( "C:", X->country); \ + PRINTX( "SAN:", gnutls_x509pki_client_get_subject_alt_name(x509_info)) + void print_info(GNUTLS_STATE state) { SRP_SERVER_AUTH_INFO srp_info; ANON_SERVER_AUTH_INFO dh_info; + X509PKI_SERVER_AUTH_INFO x509_info; const char *tmp; unsigned char sesid[32]; int sesid_size, i; + const gnutls_DN* dn; /* print session_id specific data */ gnutls_get_current_session_id( state, sesid, &sesid_size); @@ -144,6 +155,39 @@ void print_info(GNUTLS_STATE state) gnutls_anon_server_get_dh_bits(dh_info)); } + if (gnutls_get_auth_info_type(state) == GNUTLS_X509PKI) { + x509_info = gnutls_get_auth_info(state); + if (x509_info != NULL) { + switch( gnutls_x509pki_client_get_peer_certificate_status(x509_info)) { + case GNUTLS_CERT_NOT_TRUSTED: + printf("- Peer's X509 Certificate was NOT verified\n"); + break; + case GNUTLS_CERT_EXPIRED: + printf("- Peer's X509 Certificate was verified but is expired\n"); + break; + case GNUTLS_CERT_TRUSTED: + printf("- Peer's X509 Certificate was verified\n"); + break; + case GNUTLS_CERT_INVALID: + default: + printf("- Peer's X509 Certificate was invalid\n"); + break; + + } + + printf(" - Certificate info:\n"); + printf(" - Certificate version: #%d\n", gnutls_x509pki_client_get_peer_certificate_version(x509_info)); + + dn = gnutls_x509pki_client_get_peer_dn( x509_info); + PRINT_DN( dn); + + dn = gnutls_x509pki_client_get_issuer_dn( x509_info); + printf(" - Certificate Issuer's info:\n"); + PRINT_DN( dn); + } + } + + /* print state information */ tmp = gnutls_version_get_name(gnutls_get_current_version(state)); -- 2.11.4.GIT