diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2001-08-06 13:21:50 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2001-08-06 13:21:50 +0000 |
commit | b0a104f77f325659aa2a918dc9bdeaaf2071e6a6 (patch) | |
tree | 49eeba85deaf7672a2f4fbbe908de699959b14f1 | |
parent | a312f0d008595c86b793f810e7d283f1108dcca8 (diff) | |
download | gnutls-b0a104f77f325659aa2a918dc9bdeaaf2071e6a6.tar.gz |
several additions for x509 client authentication
-rw-r--r-- | lib/Makefile.am | 2 | ||||
-rw-r--r-- | lib/auth_rsa.c | 292 | ||||
-rw-r--r-- | lib/gnutls_cert.h | 2 | ||||
-rw-r--r-- | lib/gnutls_handshake.c | 8 | ||||
-rw-r--r-- | lib/gnutls_int.h | 5 | ||||
-rw-r--r-- | lib/gnutls_kx.c | 4 | ||||
-rw-r--r-- | lib/gnutls_pk.c | 26 | ||||
-rw-r--r-- | lib/gnutls_sig.c | 174 | ||||
-rw-r--r-- | lib/gnutls_sig.h | 3 | ||||
-rw-r--r-- | src/cli.c | 5 | ||||
-rw-r--r-- | src/x509/Makefile.am | 3 |
11 files changed, 427 insertions, 97 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index 91b28492b1..e68db36a3a 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -30,7 +30,7 @@ libgnutls_la_SOURCES = gnutls_record.c gnutls_compress.c debug.c \ gnutls_gcry.c ext_dnsname.c gnutls_pk.c gnutls_cert.c x509_verify.c\ gnutls_global.c gnutls_privkey.c gnutls_constate.c gnutls_anon_cred.c \ gnutls_sig_check.c pkix_asn1_tab.c pkcs1_asn1_tab.c gnutls_mem.c \ - x509_extensions.c auth_x509.c gnutls_ui.c + x509_extensions.c auth_x509.c gnutls_ui.c gnutls_sig.c libgnutls_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) diff --git a/lib/auth_rsa.c b/lib/auth_rsa.c index f3fd7bfd49..905c7667f3 100644 --- a/lib/auth_rsa.c +++ b/lib/auth_rsa.c @@ -33,21 +33,24 @@ #include <gnutls_global.h> #include <x509_verify.h> #include "debug.h" +#include <gnutls_sig.h> int gen_rsa_certificate(GNUTLS_STATE, opaque **); +int gen_rsa_client_cert_vrfy(GNUTLS_STATE, opaque **); int proc_rsa_cert_req(GNUTLS_STATE, opaque *, int); int gen_rsa_client_kx(GNUTLS_STATE, opaque **); int proc_rsa_client_kx(GNUTLS_STATE, opaque *, int); int proc_rsa_certificate(GNUTLS_STATE, opaque *, int); -MOD_AUTH_STRUCT rsa_auth_struct = { +MOD_AUTH_STRUCT rsa_auth_struct = +{ "RSA", gen_rsa_certificate, NULL, /* gen server kx */ NULL, /* gen server kx2 */ NULL, /* gen client kx0 */ gen_rsa_client_kx, - NULL, /* gen client cert vrfy */ + gen_rsa_client_cert_vrfy, /* gen client cert vrfy */ NULL, proc_rsa_certificate, @@ -67,28 +70,25 @@ typedef struct { /* This function extracts the RSA parameters from the given(?) certificate. */ -static int _gnutls_get_rsa_params( RSA_Params * params, +static int _gnutls_get_rsa_params(RSA_Params * params, MPI * mod, MPI * exp, gnutls_datum cert) { int ret = 0, result; opaque str[5 * 1024]; int len = sizeof(str); node_asn *srsa, *spk; - - if (asn1_create_structure( _gnutls_get_pkix(), "PKIX1Implicit88.Certificate", &srsa, "rsa_params") + + if (asn1_create_structure(_gnutls_get_pkix(), "PKIX1Implicit88.Certificate", &srsa, "rsa_params") != ASN_OK) { gnutls_assert(); return GNUTLS_E_ASN1_ERROR; } - - result = asn1_get_der( srsa, cert.data, cert.size); + result = asn1_get_der(srsa, cert.data, cert.size); if (result != ASN_OK) { /* couldn't decode DER */ gnutls_assert(); return GNUTLS_E_ASN1_PARSING_ERROR; } - - len = sizeof(str) - 1; result = asn1_read_value @@ -100,7 +100,6 @@ static int _gnutls_get_rsa_params( RSA_Params * params, asn1_delete_structure(srsa); return GNUTLS_E_ASN1_PARSING_ERROR; } - if (!strcmp(str, "1 2 840 113549 1 1 1")) { /* pkix-1 1 - RSA */ len = sizeof(str) - 1; result = @@ -113,20 +112,17 @@ static int _gnutls_get_rsa_params( RSA_Params * params, gnutls_assert(); return GNUTLS_E_ASN1_PARSING_ERROR; } - if (asn1_create_structure - ( _gnutls_get_pkcs(), + (_gnutls_get_pkcs(), "PKCS-1.RSAPublicKey", &spk, "rsa_public_key") != ASN_OK) { gnutls_assert(); return GNUTLS_E_ASN1_ERROR; } - if (len % 8 != 0) { gnutls_assert(); asn1_delete_structure(spk); return GNUTLS_E_UNIMPLEMENTED_FEATURE; } - result = asn1_get_der(spk, str, len / 8); if (result != ASN_OK) { @@ -134,7 +130,6 @@ static int _gnutls_get_rsa_params( RSA_Params * params, asn1_delete_structure(spk); return GNUTLS_E_ASN1_PARSING_ERROR; } - len = sizeof(str) - 1; result = asn1_read_value(spk, "rsa_public_key.modulus", str, &len); if (result != ASN_OK) { @@ -142,13 +137,11 @@ static int _gnutls_get_rsa_params( RSA_Params * params, asn1_delete_structure(spk); return GNUTLS_E_ASN1_PARSING_ERROR; } - if (gcry_mpi_scan(mod, GCRYMPI_FMT_USG, str, &len) != 0) { gnutls_assert(); asn1_delete_structure(spk); return GNUTLS_E_MPI_SCAN_FAILED; } - if (params != NULL) if (gnutls_set_datum (¶ms->rsa_modulus, str, len) < 0) { @@ -156,7 +149,6 @@ static int _gnutls_get_rsa_params( RSA_Params * params, asn1_delete_structure(spk); return GNUTLS_E_MEMORY_ERROR; } - len = sizeof(str) - 1; result = asn1_read_value(spk, "rsa_public_key.publicExponent", str, &len); @@ -168,7 +160,6 @@ static int _gnutls_get_rsa_params( RSA_Params * params, _gnutls_mpi_release(mod); return GNUTLS_E_ASN1_PARSING_ERROR; } - if (gcry_mpi_scan(exp, GCRYMPI_FMT_USG, str, &len) != 0) { gnutls_assert(); _gnutls_mpi_release(mod); @@ -188,7 +179,6 @@ static int _gnutls_get_rsa_params( RSA_Params * params, asn1_delete_structure(spk); return GNUTLS_E_MEMORY_ERROR; } - asn1_delete_structure(spk); ret = 0; @@ -214,7 +204,7 @@ static int _gnutls_get_rsa_params( RSA_Params * params, * to the gnutls_private_key structure. */ static int _gnutls_get_private_rsa_params(GNUTLS_KEY key, - gnutls_private_key *pkey) + gnutls_private_key * pkey) { key->u = gcry_mpi_copy(pkey->params[0]); @@ -238,16 +228,25 @@ int gen_rsa_certificate(GNUTLS_STATE state, opaque ** data) gnutls_assert(); return GNUTLS_E_INSUFICIENT_CRED; } - if (cred->ncerts == 0) { apr_cert_list = NULL; apr_cert_list_length = 0; apr_pkey = NULL; } else { - ind = _gnutls_find_cert_list_index( cred->cert_list, cred->ncerts, state->security_parameters.extensions.dnsname); - apr_cert_list = cred->cert_list[ind]; - apr_cert_list_length = cred->cert_list_length[ind]; - apr_pkey = &cred->pkey[ind]; + if (state->security_parameters.entity == GNUTLS_CLIENT) + ind = state->gnutls_internals.client_certificate_index; + else /* server */ + ind = _gnutls_find_cert_list_index(cred->cert_list, cred->ncerts, state->security_parameters.extensions.dnsname); + + if (ind < 0) { + apr_cert_list = NULL; + apr_cert_list_length = 0; + apr_pkey = NULL; + } else { + apr_cert_list = cred->cert_list[ind]; + apr_cert_list_length = cred->cert_list_length[ind]; + apr_pkey = &cred->pkey[ind]; + } } ret = 3; @@ -264,7 +263,6 @@ int gen_rsa_certificate(GNUTLS_STATE state, opaque ** data) gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } - WRITEuint24(ret - 3, pdata); pdata += 3; for (i = 0; i < apr_cert_list_length; i++) { @@ -276,16 +274,15 @@ int gen_rsa_certificate(GNUTLS_STATE state, opaque ** data) /* read the rsa parameters now, since later we will * not know which certificate we used! */ - if (i!=0) /* if we parsed at least one certificate */ + if (i != 0) /* if we parsed at least one certificate */ ret = _gnutls_get_private_rsa_params(state->gnutls_key, apr_pkey); else ret = 0; - + if (ret < 0) { gnutls_assert(); return ret; } - return pdatasize; } @@ -301,7 +298,7 @@ int proc_rsa_client_kx(GNUTLS_STATE state, opaque * data, int data_size) gnutls_datum ciphertext; int ret, dsize; - if (_gnutls_version_ssl3( gnutls_get_current_version( state)) == 0) { + if (_gnutls_version_ssl3(gnutls_get_current_version(state)) == 0) { /* SSL 3.0 */ ciphertext.data = data; ciphertext.size = data_size; @@ -312,7 +309,7 @@ int proc_rsa_client_kx(GNUTLS_STATE state, opaque * data, int data_size) } ret = _gnutls_pkcs1_rsa_decrypt(&plaintext, ciphertext, state->gnutls_key->u, - state->gnutls_key->A, 2); /* btype==2 */ + state->gnutls_key->A, 2); /* btype==2 */ if (ret < 0) { /* in case decryption fails then don't inform @@ -327,12 +324,12 @@ int proc_rsa_client_kx(GNUTLS_STATE state, opaque * data, int data_size) RANDOMIZE_KEY(state->gnutls_key->key, secure_malloc); } else { GNUTLS_Version ver; - - ver = gnutls_get_current_version( state); - - if ( _gnutls_version_get_major( ver) != plaintext.data[0]) + + ver = gnutls_get_current_version(state); + + if (_gnutls_version_get_major(ver) != plaintext.data[0]) ret = GNUTLS_E_DECRYPTION_FAILED; - if ( _gnutls_version_get_minor( ver) != plaintext.data[1]) + if (_gnutls_version_get_minor(ver) != plaintext.data[1]) ret = GNUTLS_E_DECRYPTION_FAILED; if (ret != 0) { _gnutls_mpi_release(&state->gnutls_key->B); @@ -361,18 +358,17 @@ int proc_rsa_certificate(GNUTLS_STATE state, opaque * data, int data_size) const X509PKI_CREDENTIALS cred; int dsize = data_size; int i, j; - gnutls_cert* peer_certificate_list; + gnutls_cert *peer_certificate_list; int peer_certificate_list_size = 0; gnutls_datum tmp; CertificateStatus verify; - + cred = _gnutls_get_cred(state->gnutls_key, GNUTLS_X509PKI, NULL); if (cred == NULL) { gnutls_assert(); return GNUTLS_E_INSUFICIENT_CRED; } - - if (state->gnutls_key->auth_info==NULL) + if (state->gnutls_key->auth_info == NULL) state->gnutls_key->auth_info = gnutls_calloc(1, sizeof(X509PKI_CLIENT_AUTH_INFO)); if (state->gnutls_key->auth_info == NULL) { gnutls_assert(); @@ -388,7 +384,6 @@ int proc_rsa_certificate(GNUTLS_STATE state, opaque * data, int data_size) gnutls_assert(); return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; } - info = state->gnutls_key->auth_info; i = dsize; @@ -406,19 +401,16 @@ int proc_rsa_certificate(GNUTLS_STATE state, opaque * data, int data_size) gnutls_assert(); return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; } - - dsize = data_size; i = dsize; peer_certificate_list = - gnutls_malloc( sizeof(gnutls_cert) * - ( peer_certificate_list_size)); + gnutls_malloc(sizeof(gnutls_cert) * + (peer_certificate_list_size)); - if ( peer_certificate_list == NULL) { + if (peer_certificate_list == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } - p = data + 3; i = data_size - 3; j = 0; @@ -432,12 +424,11 @@ int proc_rsa_certificate(GNUTLS_STATE state, opaque * data, int data_size) tmp.size = len; tmp.data = p; - if ( (ret=_gnutls_cert2gnutlsCert( &peer_certificate_list[j], tmp)) < 0) { + if ((ret = _gnutls_cert2gnutlsCert(&peer_certificate_list[j], tmp)) < 0) { gnutls_assert(); - gnutls_free( peer_certificate_list); + gnutls_free(peer_certificate_list); return ret; } - p += len; i -= len + 3; j++; @@ -446,22 +437,20 @@ int proc_rsa_certificate(GNUTLS_STATE state, opaque * data, int data_size) /* store the required parameters for the handshake */ if ((ret = - _gnutls_get_rsa_params( NULL, &state->gnutls_key->A, &state->gnutls_key->u, + _gnutls_get_rsa_params(NULL, &state->gnutls_key->A, &state->gnutls_key->u, peer_certificate_list[0].raw)) < 0) { gnutls_assert(); - gnutls_free( peer_certificate_list); + gnutls_free(peer_certificate_list); return ret; } - - /* Verify certificate */ - verify = gnutls_verify_certificate( peer_certificate_list, peer_certificate_list_size, - cred->ca_list, cred->ncas, NULL, 0); - - _gnutls_copy_x509_client_auth_info( info, &peer_certificate_list[0], verify); + verify = gnutls_verify_certificate(peer_certificate_list, peer_certificate_list_size, + cred->ca_list, cred->ncas, NULL, 0); + + _gnutls_copy_x509_client_auth_info(info, &peer_certificate_list[0], verify); - gnutls_free( peer_certificate_list); + gnutls_free(peer_certificate_list); return 0; } @@ -475,7 +464,7 @@ int gen_rsa_client_kx(GNUTLS_STATE state, opaque ** data) MPI pkey, n; int ret; GNUTLS_Version ver; - + if (auth == NULL) { /* this shouldn't have happened. The proc_certificate * function should have detected that. @@ -483,13 +472,12 @@ int gen_rsa_client_kx(GNUTLS_STATE state, opaque ** data) gnutls_assert(); return GNUTLS_E_INSUFICIENT_CRED; } - RANDOMIZE_KEY(state->gnutls_key->key, secure_malloc); - - ver = gnutls_get_current_version( state); - - state->gnutls_key->key.data[0] = _gnutls_version_get_major( ver); - state->gnutls_key->key.data[1] = _gnutls_version_get_minor( ver); + + ver = gnutls_get_current_version(state); + + state->gnutls_key->key.data[0] = _gnutls_version_get_major(ver); + state->gnutls_key->key.data[1] = _gnutls_version_get_minor(ver); if ((ret = _gnutls_pkcs1_rsa_encrypt(&sdata, state->gnutls_key->key, state->gnutls_key->u, state->gnutls_key->A, 2)) < 0) { @@ -498,11 +486,10 @@ int gen_rsa_client_kx(GNUTLS_STATE state, opaque ** data) _gnutls_mpi_release(&n); return ret; } - _gnutls_mpi_release(&state->gnutls_key->A); _gnutls_mpi_release(&state->gnutls_key->u); - if (_gnutls_version_ssl3( ver) == 0) { + if (_gnutls_version_ssl3(ver) == 0) { /* SSL 3.0 */ *data = sdata.data; return sdata.size; @@ -521,26 +508,103 @@ int gen_rsa_client_kx(GNUTLS_STATE state, opaque ** data) } -#define RSA_SIGN 1 +/* Finds the appropriate certificate depending on the cA Distinguished name + * advertized by the server + */ +static int _gnutls_find_acceptable_client_cert( const X509PKI_CREDENTIALS cred, const opaque* data, + int data_size, int *ind) { +node_asn *dn; +int result, size; +int indx = -1; +int start, end, len, i, j; + + + do { + + DECR_LEN(data_size, 2); + size = READuint16(data); + data += 2; + + for(i=0;i<cred->ncerts;i++) { + + for (j=0;j<cred->cert_list_length[i];j++) { + if (asn1_create_structure(_gnutls_get_pkix(), "PKIX1Implicit88.Certificate", &dn, "dn") != ASN_OK) { + gnutls_assert(); + return GNUTLS_E_ASN1_ERROR; + } + + result = asn1_get_der( dn, cred->cert_list[i][j].raw.data, cred->cert_list[i][j].raw.size); + if (result != ASN_OK) { + /* couldn't decode DER */ + gnutls_assert(); + asn1_delete_structure( dn); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + result = asn1_get_start_end_der( dn, cred->cert_list[i][j].raw.data, cred->cert_list[i][j].raw.size, + "dn.tbsCertificate.issuer", &start, &end); + + if (result != ASN_OK) { + /* couldn't decode DER */ + gnutls_assert(); + asn1_delete_structure( dn); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + asn1_delete_structure( dn); + + len = end - start + 1; + + if ( len != size) continue; + + if (memcmp( + &cred->cert_list[i][j].raw.data[start], + data, len) == 0 ) { + indx = i; + break; + } + } + if (indx != -1) + break; + } + + if (indx != -1) + break; + /* move to next record */ + data_size -= size; + if (data_size <= 0) + break; + + data += size; + + } while (1); + + if (indx==-1 && cred->ncerts > 0) /* use the first certificate */ + indx = 0; + + *ind = indx; + return 0; +} + +#define RSA_SIGN 1 int proc_rsa_cert_req(GNUTLS_STATE state, opaque * data, int data_size) { - int size; + int size, ret; opaque *p = data; const X509PKI_CREDENTIALS cred; int dsize = data_size; int i; int found; - + int ind; + cred = _gnutls_get_cred(state->gnutls_key, GNUTLS_X509PKI, NULL); if (cred == NULL) { gnutls_assert(); return GNUTLS_E_INSUFICIENT_CRED; } - state->gnutls_key->certificate_requested = 1; - if (state->gnutls_key->auth_info==NULL) + if (state->gnutls_key->auth_info == NULL) state->gnutls_key->auth_info = gnutls_calloc(1, sizeof(X509PKI_CLIENT_AUTH_INFO)); if (state->gnutls_key->auth_info == NULL) { gnutls_assert(); @@ -553,29 +617,87 @@ int proc_rsa_cert_req(GNUTLS_STATE state, opaque * data, int data_size) p += 1; found = 0; - for (i=0;i<size;i++,p++) { - DECR_LEN( dsize, 1); - if (*p==RSA_SIGN) found=1; + for (i = 0; i < size; i++, p++) { + DECR_LEN(dsize, 1); + if (*p == RSA_SIGN) + found = 1; } - - if (found==0) { + + if (found == 0) { gnutls_assert(); return GNUTLS_E_UNKNOWN_KX_ALGORITHM; } - - - DECR_LEN(dsize, 2); size = READuint16(p); p += 2; -fprintf(stderr, "DN size: %d\n", size); if (size == 0) { return 0; } -#warning "FIND CERTIFICATE TO SEND" -//fprintf(stderr, "DN: %s\n", _gnutls_bin2hex( p, size)); + if ( (ret = _gnutls_find_acceptable_client_cert( cred, p, size, &ind)) < 0) { + gnutls_assert(); + return ret; + } + + /* put the index of the client certificate to use + */ + state->gnutls_internals.client_certificate_index = ind; return 0; } + +int gen_rsa_client_cert_vrfy(GNUTLS_STATE state, opaque ** data) +{ + const X509PKI_CREDENTIALS cred; + int ret, ind; + gnutls_cert *apr_cert_list; + gnutls_private_key *apr_pkey; + int apr_cert_list_length, size; + gnutls_datum signature; + + cred = _gnutls_get_cred(state->gnutls_key, GNUTLS_X509PKI, NULL); + if (cred == NULL) { + gnutls_assert(); + return GNUTLS_E_INSUFICIENT_CRED; + } + if (cred->ncerts == 0) { + apr_cert_list = NULL; + apr_cert_list_length = 0; + apr_pkey = NULL; + } else { + ind = state->gnutls_internals.client_certificate_index; + if (ind < 0) { + apr_cert_list = NULL; + apr_cert_list_length = 0; + apr_pkey = NULL; + } else { + apr_cert_list = cred->cert_list[ind]; + apr_cert_list_length = cred->cert_list_length[ind]; + apr_pkey = &cred->pkey[ind]; + } + } + + if (apr_pkey != NULL) { + if ( (ret=_gnutls_generate_sig( state, apr_pkey, &signature)) < 0) { + gnutls_assert(); + return ret; + } + } else { + gnutls_assert(); + return 0; + } + + *data = gnutls_malloc(signature.size+2); + if (*data==NULL) { + gnutls_free_datum( &signature); + return GNUTLS_E_MEMORY_ERROR; + } + size = signature.size; + WRITEuint16( size, *data); + + memcpy( &(*data)[2], signature.data, size); + + gnutls_free_datum( &signature); + return size+2; +} diff --git a/lib/gnutls_cert.h b/lib/gnutls_cert.h index b0bd67ab0b..7cbb54fd93 100644 --- a/lib/gnutls_cert.h +++ b/lib/gnutls_cert.h @@ -5,7 +5,7 @@ #include <gnutls_ui.h> -typedef struct { +typedef struct gnutls_cert { MPI *params; /* the size of params depends on the public * key algorithm */ diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c index 3842a09303..4ccbe83124 100644 --- a/lib/gnutls_handshake.c +++ b/lib/gnutls_handshake.c @@ -1481,8 +1481,8 @@ int gnutls_handshake_finish(SOCKET cd, GNUTLS_STATE state) { return ret; } -#warning "FIX THIS REQUEST" - /* receive the server certificate request */ + /* receive the server certificate request - if any + */ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */ ret = _gnutls_recv_server_certificate_request(cd, state); if (ret < 0) { @@ -1492,7 +1492,8 @@ int gnutls_handshake_finish(SOCKET cd, GNUTLS_STATE state) { return ret; } - /* receive the server key exchange (B) (SRP only) */ + /* receive the server key exchange (B) (SRP only) + */ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */ ret = _gnutls_recv_server_kx_message2(cd, state); if (ret < 0) { @@ -1532,6 +1533,7 @@ int gnutls_handshake_finish(SOCKET cd, GNUTLS_STATE state) { gnutls_clearHashDataBuffer(state); return ret; } + /* send client certificate verify */ if (state->gnutls_internals.resumed == RESUME_FALSE) /* if we are not resuming */ ret = diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 25defee769..1841181125 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -326,6 +326,11 @@ typedef struct { /* keeps the headers of the handshake packet */ HANDSHAKE_HEADER_BUFFER handshake_header_buffer; + int client_certificate_index; /* holds + * the index of the client + * certificate to use. -1 + * if none. + */ } GNUTLS_INTERNALS; struct GNUTLS_STATE_INT { diff --git a/lib/gnutls_kx.c b/lib/gnutls_kx.c index 21d6e5a5c7..14a4dc52e2 100644 --- a/lib/gnutls_kx.c +++ b/lib/gnutls_kx.c @@ -236,8 +236,10 @@ int _gnutls_send_client_certificate_verify(SOCKET cd, GNUTLS_STATE state) _gnutls_log( "Sending client certificate verify message\n"); #endif data_size = state->gnutls_internals.auth_struct->gnutls_generate_client_cert_vrfy( state, &data); - if (data_size < 0) + if (data_size < 0) { + gnutls_assert(); return data_size; + } ret = _gnutls_send_handshake(cd, state, data, data_size, diff --git a/lib/gnutls_pk.c b/lib/gnutls_pk.c index 4c957a63cb..0d42dd4f8d 100644 --- a/lib/gnutls_pk.c +++ b/lib/gnutls_pk.c @@ -29,6 +29,7 @@ #include <gnutls_datum.h> #include "debug.h" + /* Do PKCS-1 RSA encryption. * pkey is the public key and n the modulus. */ @@ -63,11 +64,30 @@ int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext, gnutls_datum plaintext, psize = k - 3 - plaintext.size; ps = &edata[2]; - _gnutls_get_random(ps, psize, GNUTLS_WEAK_RANDOM); - for (i = 0; i < psize; i++) { - if (ps[i] == 0) + switch(btype) { + case 2: + _gnutls_get_random(ps, psize, GNUTLS_WEAK_RANDOM); + for (i = 0; i < psize; i++) { + if (ps[i] == 0) + ps[i] = 0xff; + } + break; + case 1: + for (i = 0; i < psize; i++) ps[i] = 0xff; + break; +#ifdef ALLOW_BLOCK_0 + case 0: + for (i = 0; i < psize; i++) { + ps[i] = 0x00; + } + break; +#endif + default: + gnutls_assert(); + return GNUTLS_E_UNKNOWN_ERROR; } + ps[psize] = 0; memcpy(&ps[psize + 1], plaintext.data, plaintext.size); diff --git a/lib/gnutls_sig.c b/lib/gnutls_sig.c new file mode 100644 index 0000000000..5ee2a3399e --- /dev/null +++ b/lib/gnutls_sig.c @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2001 Nikos Mavroyanopoulos + * + * This file is part of GNUTLS. + * + * GNUTLS is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GNUTLS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <gnutls_int.h> +#include <gnutls_errors.h> +#include <x509_b64.h> +#include <auth_x509.h> +#include <gnutls_cert.h> +#include <x509_asn1.h> +#include <x509_der.h> +#include <gnutls_datum.h> +#include <gnutls_gcry.h> +#include <gnutls_privkey.h> +#include <gnutls_global.h> +#include <gnutls_pk.h> +#include <debug.h> +#include <gnutls_buffers.h> +#include <gnutls_sig.h> + +int _gnutls_generate_sig( GNUTLS_STATE state, gnutls_private_key *pkey, gnutls_datum *signature) { +opaque digest[20+16]; +gnutls_datum data; +GNUTLS_HASH_HANDLE td; +int size = gnutls_getHashDataBufferSize( state); +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(pkey->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_generate_sig( GNUTLS_MAC_MD5, pkey, &data, signature); + break; + default: + gnutls_free_datum( &data); + ret = GNUTLS_E_UNIMPLEMENTED_FEATURE; + break; + } + + return ret; + +} + +static int _gnutls_digestinfo_encode( opaque* data, int data_size, char* OID, gnutls_datum* der) { +node_asn *di; +int result; + + if (asn1_create_structure( _gnutls_get_pkcs(), + "PKCS-1.DigestInfo", &di, "di") != ASN_OK) { + gnutls_assert(); + return GNUTLS_E_ASN1_ERROR; + } + + result = asn1_write_value( di, "di.digestAlgorithm.algorithm", OID, 1); + if (result!=ASN_OK) { + gnutls_assert(); + return GNUTLS_E_ASN1_ERROR; + } + + result = asn1_write_value( di, "di.digestAlgorithm.parameters", NULL, 0); + if (result!=ASN_OK) { + gnutls_assert(); + return GNUTLS_E_ASN1_ERROR; + } + + result = asn1_write_value( di, "di.digest", data, data_size); + if (result!=ASN_OK) { + gnutls_assert(); + return GNUTLS_E_ASN1_ERROR; + } + + der->size = data_size + 200; + der->data = gnutls_malloc( der->size); + if (der->data==NULL) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + result = asn1_create_der( di, "di", der->data, &der->size); + if (result!=ASN_OK) { + gnutls_assert(); + gnutls_free_datum( der); + return GNUTLS_E_ASN1_ERROR; + } + + return 0; +} + +int _gnutls_pkcs1_rsa_generate_sig( MACAlgorithm hash_algo, gnutls_private_key *pkey, const gnutls_datum *data, gnutls_datum *signature) { + GNUTLS_HASH_HANDLE hd; + opaque digest[MAX_HASH_SIZE]; + int digest_size = gnutls_hash_get_algo_len( hash_algo), ret; + char OID[40]; + gnutls_datum der; + + if (hash_algo==GNUTLS_MAC_MD5) + strcpy(OID, "1 2 840 113549 2 5"); + else if (hash_algo==GNUTLS_MAC_SHA) + strcpy(OID, "1 3 14 3 2 26"); + else { + gnutls_assert(); + return GNUTLS_E_UNKNOWN_MAC_ALGORITHM; + } + + /* hash data */ + hd = gnutls_hash_init( hash_algo); + if (hd==NULL) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + gnutls_hash( hd, data->data, data->size); + gnutls_hash_deinit( hd, digest); + + + /* encode digest to DigestInfo (der) */ + if ( (ret=_gnutls_digestinfo_encode( digest, digest_size, OID, &der)) < 0) { + gnutls_assert(); + return ret; + } + + /* encrypt der */ + if ( (ret=_gnutls_pkcs1_rsa_encrypt( signature, der, pkey->params[0], pkey->params[1], 1)) < 0) { + gnutls_assert(); + return ret; + } + + gnutls_free_datum( &der); + return 0; +} diff --git a/lib/gnutls_sig.h b/lib/gnutls_sig.h index c8a759884f..6253060a31 100644 --- a/lib/gnutls_sig.h +++ b/lib/gnutls_sig.h @@ -1,3 +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); - +int _gnutls_pkcs1_rsa_generate_sig( MACAlgorithm hash_algo, 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); @@ -39,6 +39,8 @@ #define MAX(X,Y) (X >= Y ? X : Y); #define CAFILE "x509/ca.pem" #define CRLFILE NULL +#define CLIKEYFILE "x509/clikey.pem" +#define CLICERTFILE "x509/clicert.pem" #define PRINTX(x,y) if (y[0]!=0) printf(" - %s %s\n", x, y) #define PRINT_DN(X) PRINTX( "CN:", X->common_name); \ @@ -144,11 +146,12 @@ int main(int argc, char** argv) /* X509 stuff */ - if (gnutls_allocate_x509_client_sc( &xcred, 0) < 0) { /* no priv key */ + if (gnutls_allocate_x509_client_sc( &xcred, 1) < 0) { fprintf(stderr, "memory error\n"); exit(1); } gnutls_set_x509_client_trust( xcred, CAFILE, CRLFILE); + gnutls_set_x509_client_key( xcred, CLICERTFILE, CLIKEYFILE); /* SRP stuff */ if (gnutls_allocate_srp_client_sc( &cred)<0) { diff --git a/src/x509/Makefile.am b/src/x509/Makefile.am index 2dec0d7d63..f6168077cf 100644 --- a/src/x509/Makefile.am +++ b/src/x509/Makefile.am @@ -1 +1,2 @@ -EXTRA_DIST = ca.pem cert.pem key.pem +EXTRA_DIST = ca.pem cert.pem key.pem clikey.pem clicert.pem + |