summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2001-08-06 13:21:50 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2001-08-06 13:21:50 +0000
commitb0a104f77f325659aa2a918dc9bdeaaf2071e6a6 (patch)
tree49eeba85deaf7672a2f4fbbe908de699959b14f1
parenta312f0d008595c86b793f810e7d283f1108dcca8 (diff)
downloadgnutls-b0a104f77f325659aa2a918dc9bdeaaf2071e6a6.tar.gz
several additions for x509 client authentication
-rw-r--r--lib/Makefile.am2
-rw-r--r--lib/auth_rsa.c292
-rw-r--r--lib/gnutls_cert.h2
-rw-r--r--lib/gnutls_handshake.c8
-rw-r--r--lib/gnutls_int.h5
-rw-r--r--lib/gnutls_kx.c4
-rw-r--r--lib/gnutls_pk.c26
-rw-r--r--lib/gnutls_sig.c174
-rw-r--r--lib/gnutls_sig.h3
-rw-r--r--src/cli.c5
-rw-r--r--src/x509/Makefile.am3
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
(&params->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);
diff --git a/src/cli.c b/src/cli.c
index be62a3310f..c1e567d161 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -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
+